Author: ericwf Date: Sat Apr 15 20:51:04 2017 New Revision: 300406 URL: http://llvm.org/viewvc/llvm-project?rev=300406&view=rev Log: 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<T[]>::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<T[]> from nullptr. Libc++ had previously implemented this issue, but the suggested resolution still broke initialization from NULL. This patch re-works the unique_ptr<T[]>(Up, deleter) overloads so that they accept NULL as well as nullptr. Added: libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.pass.cpp libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.pass.cpp Modified: libcxx/trunk/include/memory libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move.pass.cpp libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/default.pass.cpp libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move.pass.cpp libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.runtime.pass.cpp libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.single.pass.cpp libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/nullptr.pass.cpp libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer.pass.cpp libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer_deleter.fail.cpp libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer_deleter.pass.cpp libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.dtor/null.pass.cpp libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.modifiers/release.pass.cpp libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.modifiers/reset.pass.cpp libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.modifiers/swap.pass.cpp libcxx/trunk/test/support/deleter_types.h libcxx/trunk/test/support/test_workarounds.h libcxx/trunk/www/cxx1z_status.html Modified: libcxx/trunk/include/memory URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/memory?rev=300406&r1=300405&r2=300406&view=diff ============================================================================== --- libcxx/trunk/include/memory (original) +++ libcxx/trunk/include/memory Sat Apr 15 20:51:04 2017 @@ -2313,412 +2313,587 @@ public: } }; + +#ifndef _LIBCPP_CXX03_LANG +template <class _Deleter> +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 <class _Deleter> +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 <class _Deleter> +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 _Tp, class _Dp = default_delete<_Tp> > -class _LIBCPP_TEMPLATE_VIS unique_ptr -{ +class _LIBCPP_TEMPLATE_VIS unique_ptr { 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; + + static_assert(!is_rvalue_reference<deleter_type>::value, + "the specified deleter type cannot be an rvalue reference"); + private: - __compressed_pair<pointer, deleter_type> __ptr_; + __compressed_pair<pointer, deleter_type> __ptr_; -#ifdef _LIBCPP_HAS_NO_RVALUE_REFERENCES - unique_ptr(unique_ptr&); - template <class _Up, class _Ep> - unique_ptr(unique_ptr<_Up, _Ep>&); - unique_ptr& operator=(unique_ptr&); - template <class _Up, class _Ep> - unique_ptr& operator=(unique_ptr<_Up, _Ep>&); -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES - - struct __nat {int __for_bool_;}; - - typedef typename remove_reference<deleter_type>::type& _Dp_reference; - typedef typename remove_reference<typename add_const<deleter_type>::type>::type& - _Dp_const_reference; -public: - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR unique_ptr() _NOEXCEPT - : __ptr_(pointer()) - { - static_assert(!is_pointer<deleter_type>::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<deleter_type>::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<deleter_type>::value, - "unique_ptr constructed with null function pointer deleter"); - } + struct __nat { int __for_bool_; }; -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES - _LIBCPP_INLINE_VISIBILITY unique_ptr(pointer __p, typename conditional< - is_reference<deleter_type>::value, - deleter_type, - typename add_lvalue_reference<const deleter_type>::type>::type __d) - _NOEXCEPT - : __ptr_(__p, __d) {} - - _LIBCPP_INLINE_VISIBILITY unique_ptr(pointer __p, typename remove_reference<deleter_type>::type&& __d) - _NOEXCEPT - : __ptr_(__p, _VSTD::move(__d)) - { - static_assert(!is_reference<deleter_type>::value, "rvalue deleter bound to reference"); - } - _LIBCPP_INLINE_VISIBILITY unique_ptr(unique_ptr&& __u) _NOEXCEPT - : __ptr_(__u.release(), _VSTD::forward<deleter_type>(__u.get_deleter())) {} - template <class _Up, class _Ep> - _LIBCPP_INLINE_VISIBILITY - unique_ptr(unique_ptr<_Up, _Ep>&& __u, - typename enable_if - < - !is_array<_Up>::value && - is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>::value && - is_convertible<_Ep, deleter_type>::value && - ( - !is_reference<deleter_type>::value || - is_same<deleter_type, _Ep>::value - ), - __nat - >::type = __nat()) _NOEXCEPT - : __ptr_(__u.release(), _VSTD::forward<_Ep>(__u.get_deleter())) {} +#ifndef _LIBCPP_CXX03_LANG + typedef __unique_ptr_deleter_sfinae<_Dp> _SFINAE; + + template <bool _Dummy> + using _LValRefType = + typename __dependent_type<_SFINAE, _Dummy>::__lval_ref_type; + + template <bool _Dummy> + using _GoodRValRefType = + typename __dependent_type<_SFINAE, _Dummy>::__good_rval_ref_type; + + template <bool _Dummy> + using _BadRValRefType = + typename __dependent_type<_SFINAE, _Dummy>::__bad_rval_ref_type; + + template <bool _Dummy, class _Deleter = typename __dependent_type< + __identity<deleter_type>, _Dummy>::type> + using _EnableIfDeleterDefaultConstructible = + typename enable_if<is_default_constructible<_Deleter>::value && + !is_pointer<_Deleter>::value>::type; + + template <class _ArgType> + using _EnableIfDeleterConstructible = + typename enable_if<is_constructible<deleter_type, _ArgType>::value>::type; + + template <class _UPtr, class _Up> + using _EnableIfMoveConvertible = typename enable_if< + is_convertible<typename _UPtr::pointer, pointer>::value && + !is_array<_Up>::value + >::type; + + template <class _UDel> + 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 <class _UDel> + using _EnableIfDeleterAssignable = typename enable_if< + is_assignable<_Dp&, _UDel&&>::value + >::type; + +public: + template <bool _Dummy = true, + class = _EnableIfDeleterDefaultConstructible<_Dummy>> + _LIBCPP_INLINE_VISIBILITY + constexpr unique_ptr() noexcept : __ptr_(pointer()) {} + + template <bool _Dummy = true, + class = _EnableIfDeleterDefaultConstructible<_Dummy>> + _LIBCPP_INLINE_VISIBILITY + constexpr unique_ptr(nullptr_t) noexcept : __ptr_(pointer()) {} + + template <bool _Dummy = true, + class = _EnableIfDeleterDefaultConstructible<_Dummy>> + _LIBCPP_INLINE_VISIBILITY + explicit unique_ptr(pointer __p) noexcept : __ptr_(__p) {} + + template <bool _Dummy = true, + class = _EnableIfDeleterConstructible<_LValRefType<_Dummy>>> + _LIBCPP_INLINE_VISIBILITY + unique_ptr(pointer __p, _LValRefType<_Dummy> __d) noexcept + : __ptr_(__p, __d) {} + + template <bool _Dummy = true, + class = _EnableIfDeleterConstructible<_GoodRValRefType<_Dummy>>> + _LIBCPP_INLINE_VISIBILITY + unique_ptr(pointer __p, _GoodRValRefType<_Dummy> __d) noexcept + : __ptr_(__p, _VSTD::move(__d)) { + static_assert(!is_reference<deleter_type>::value, + "rvalue deleter bound to reference"); + } + + template <bool _Dummy = true, + class = _EnableIfDeleterConstructible<_BadRValRefType<_Dummy>>> + _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<deleter_type>(__u.get_deleter())) { + } + + template <class _Up, class _Ep, + class = _EnableIfMoveConvertible<unique_ptr<_Up, _Ep>, _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 <class _Up> - _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()) - { - } + template <class _Up> + _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<deleter_type>(__u.get_deleter()); - return *this; - } - - template <class _Up, class _Ep> - _LIBCPP_INLINE_VISIBILITY - typename enable_if - < - !is_array<_Up>::value && - is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>::value && - is_assignable<deleter_type&, _Ep&&>::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<unique_ptr>() - { - return __rv<unique_ptr>(*this); - } - - _LIBCPP_INLINE_VISIBILITY unique_ptr(__rv<unique_ptr> __u) - : __ptr_(__u->release(), _VSTD::forward<deleter_type>(__u->get_deleter())) {} - - template <class _Up, class _Ep> - _LIBCPP_INLINE_VISIBILITY - typename enable_if< - !is_array<_Up>::value && - is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>::value && - is_assignable<deleter_type&, _Ep&>::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& operator=(unique_ptr&& __u) _NOEXCEPT { + reset(__u.release()); + __ptr_.second() = _VSTD::forward<deleter_type>(__u.get_deleter()); + return *this; + } + + template <class _Up, class _Ep, + class = _EnableIfMoveConvertible<unique_ptr<_Up, _Ep>, _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 <class _Up, class _Ep> unique_ptr(unique_ptr<_Up, _Ep>&); - _LIBCPP_INLINE_VISIBILITY unique_ptr(pointer __p, deleter_type __d) - : __ptr_(_VSTD::move(__p), _VSTD::move(__d)) {} + unique_ptr& operator=(unique_ptr&); + template <class _Up, class _Ep> unique_ptr& operator=(unique_ptr<_Up, _Ep>&); + +public: + _LIBCPP_INLINE_VISIBILITY + unique_ptr() : __ptr_(pointer()) + { + static_assert(!is_pointer<deleter_type>::value, + "unique_ptr constructed with null function pointer deleter"); + static_assert(is_default_constructible<deleter_type>::value, + "unique_ptr::deleter_type is not default constructible"); + } + _LIBCPP_INLINE_VISIBILITY + unique_ptr(nullptr_t) : __ptr_(pointer()) + { + static_assert(!is_pointer<deleter_type>::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<deleter_type>::value, + "unique_ptr constructed with null function pointer deleter"); + } + + _LIBCPP_INLINE_VISIBILITY + operator __rv<unique_ptr>() { + return __rv<unique_ptr>(*this); + } + + _LIBCPP_INLINE_VISIBILITY + unique_ptr(__rv<unique_ptr> __u) + : __ptr_(__u->release(), + _VSTD::forward<deleter_type>(__u->get_deleter())) {} + + template <class _Up, class _Ep> + _LIBCPP_INLINE_VISIBILITY + typename enable_if< + !is_array<_Up>::value && + is_convertible<typename unique_ptr<_Up, _Ep>::pointer, + pointer>::value && + is_assignable<deleter_type&, _Ep&>::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 <class _Up> - _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;} + template <class _Up> + _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 + ~unique_ptr() { reset(); } - _LIBCPP_INLINE_VISIBILITY void swap(unique_ptr& __u) _NOEXCEPT - {__ptr_.swap(__u.__ptr_);} + _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 <class _From, class _ToUnique> +struct __check_array_pointer_conversion : is_same<_From, typename _ToUnique::pointer> {}; + +template <class _FromElem, class _ToUnique> +struct __check_array_pointer_conversion<_FromElem*, _ToUnique> + : integral_constant<bool, + is_same<_FromElem*, typename _ToUnique::pointer>::value || + (is_same<typename _ToUnique::pointer, typename _ToUnique::element_type*>::value && + is_convertible<_FromElem(*)[], typename _ToUnique::element_type(*)[]>::value) + > +{}; + template <class _Tp, class _Dp> -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<pointer, deleter_type> __ptr_; + __compressed_pair<pointer, deleter_type> __ptr_; -#ifdef _LIBCPP_HAS_NO_RVALUE_REFERENCES - unique_ptr(unique_ptr&); - template <class _Up> - unique_ptr(unique_ptr<_Up>&); - unique_ptr& operator=(unique_ptr&); - template <class _Up> - unique_ptr& operator=(unique_ptr<_Up>&); -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES - - struct __nat {int __for_bool_;}; - - typedef typename remove_reference<deleter_type>::type& _Dp_reference; - typedef typename remove_reference<typename add_const<deleter_type>::type>::type& - _Dp_const_reference; -public: - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR unique_ptr() _NOEXCEPT - : __ptr_(pointer()) - { - static_assert(!is_pointer<deleter_type>::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<deleter_type>::value, - "unique_ptr constructed with null function pointer deleter"); - } -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES - template <class _Pp> - _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<deleter_type>::value, - "unique_ptr constructed with null function pointer deleter"); - } + struct __nat { int __for_bool_; }; - template <class _Pp> - _LIBCPP_INLINE_VISIBILITY unique_ptr(_Pp __p, typename conditional< - is_reference<deleter_type>::value, - deleter_type, - typename add_lvalue_reference<const deleter_type>::type>::type __d, - typename enable_if<__same_or_less_cv_qualified<_Pp, pointer>::value, __nat>::type = __nat()) - _NOEXCEPT - : __ptr_(__p, __d) {} - - _LIBCPP_INLINE_VISIBILITY unique_ptr(nullptr_t, typename conditional< - is_reference<deleter_type>::value, - deleter_type, - typename add_lvalue_reference<const deleter_type>::type>::type __d) - _NOEXCEPT - : __ptr_(pointer(), __d) {} - - template <class _Pp> - _LIBCPP_INLINE_VISIBILITY unique_ptr(_Pp __p, - typename remove_reference<deleter_type>::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<deleter_type>::value, "rvalue deleter bound to reference"); - } + typedef deleter_type& _Dp_reference; + typedef typename remove_reference<typename add_const<deleter_type>::type>::type& + _Dp_const_reference; + +#ifndef _LIBCPP_CXX03_LANG + typedef __unique_ptr_deleter_sfinae<_Dp> _SFINAE; + + template <bool _Dummy> + using _LValRefType = + typename __dependent_type<_SFINAE, _Dummy>::__lval_ref_type; + + template <bool _Dummy> + using _GoodRValRefType = + typename __dependent_type<_SFINAE, _Dummy>::__good_rval_ref_type; + + template <bool _Dummy> + using _BadRValRefType = + typename __dependent_type<_SFINAE, _Dummy>::__bad_rval_ref_type; + + template <bool _Dummy, class _Deleter = typename __dependent_type< + __identity<deleter_type>, _Dummy>::type> + using _EnableIfDeleterDefaultConstructible = + typename enable_if<is_default_constructible<_Deleter>::value && + !is_pointer<_Deleter>::value>::type; + + template <class _ArgType> + using _EnableIfDeleterConstructible = + typename enable_if<is_constructible<deleter_type, _ArgType>::value>::type; + + template <class _Pp> + using _EnableIfPointerConvertible = typename enable_if< + __check_array_pointer_conversion<_Pp, unique_ptr>::value + >::type; + + template <class _UPtr, class _Up, + class _ElemT = typename _UPtr::element_type> + using _EnableIfMoveConvertible = typename enable_if< + is_array<_Up>::value && + is_same<pointer, element_type*>::value && + is_same<typename _UPtr::pointer, _ElemT*>::value && + is_convertible<_ElemT(*)[], element_type(*)[]>::value + >::type; + + template <class _UDel> + 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 <class _UDel> + using _EnableIfDeleterAssignable = typename enable_if< + is_assignable<_Dp&, _UDel&&>::value + >::type; - _LIBCPP_INLINE_VISIBILITY unique_ptr(nullptr_t, typename remove_reference<deleter_type>::type&& __d) - _NOEXCEPT - : __ptr_(pointer(), _VSTD::move(__d)) - { - static_assert(!is_reference<deleter_type>::value, "rvalue deleter bound to reference"); - } +public: + template <bool _Dummy = true, + class = _EnableIfDeleterDefaultConstructible<_Dummy>> + _LIBCPP_INLINE_VISIBILITY + constexpr unique_ptr() noexcept : __ptr_(pointer()) {} + + template <bool _Dummy = true, + class = _EnableIfDeleterDefaultConstructible<_Dummy>> + _LIBCPP_INLINE_VISIBILITY + constexpr unique_ptr(nullptr_t) noexcept : __ptr_(pointer()) {} + + template <class _Pp, bool _Dummy = true, + class = _EnableIfDeleterDefaultConstructible<_Dummy>, + class = _EnableIfPointerConvertible<_Pp>> + _LIBCPP_INLINE_VISIBILITY + explicit unique_ptr(_Pp __p) noexcept + : __ptr_(__p) {} + + template <class _Pp, bool _Dummy = true, + class = _EnableIfDeleterConstructible<_LValRefType<_Dummy>>, + class = _EnableIfPointerConvertible<_Pp>> + _LIBCPP_INLINE_VISIBILITY + unique_ptr(_Pp __p, _LValRefType<_Dummy> __d) noexcept + : __ptr_(__p, __d) {} + + template <bool _Dummy = true, + class = _EnableIfDeleterConstructible<_LValRefType<_Dummy>>> + _LIBCPP_INLINE_VISIBILITY + unique_ptr(nullptr_t, _LValRefType<_Dummy> __d) noexcept + : __ptr_(nullptr, __d) {} + + template <class _Pp, bool _Dummy = true, + class = _EnableIfDeleterConstructible<_GoodRValRefType<_Dummy>>, + class = _EnableIfPointerConvertible<_Pp>> + _LIBCPP_INLINE_VISIBILITY + unique_ptr(_Pp __p, _GoodRValRefType<_Dummy> __d) noexcept + : __ptr_(__p, _VSTD::move(__d)) { + static_assert(!is_reference<deleter_type>::value, + "rvalue deleter bound to reference"); + } + + template <bool _Dummy = true, + class = _EnableIfDeleterConstructible<_GoodRValRefType<_Dummy>>> + _LIBCPP_INLINE_VISIBILITY + unique_ptr(nullptr_t, _GoodRValRefType<_Dummy> __d) noexcept + : __ptr_(nullptr, _VSTD::move(__d)) { + static_assert(!is_reference<deleter_type>::value, + "rvalue deleter bound to reference"); + } + + template <class _Pp, bool _Dummy = true, + class = _EnableIfDeleterConstructible<_BadRValRefType<_Dummy>>, + 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<deleter_type>(__u.get_deleter())) { + } + + _LIBCPP_INLINE_VISIBILITY + unique_ptr& operator=(unique_ptr&& __u) noexcept { + reset(__u.release()); + __ptr_.second() = _VSTD::forward<deleter_type>(__u.get_deleter()); + return *this; + } + + template <class _Up, class _Ep, + class = _EnableIfMoveConvertible<unique_ptr<_Up, _Ep>, _Up>, + class = _EnableIfDeleterConvertible<_Ep> + > + _LIBCPP_INLINE_VISIBILITY + unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept + : __ptr_(__u.release(), _VSTD::forward<deleter_type>(__u.get_deleter())) { + } + + template <class _Up, class _Ep, + class = _EnableIfMoveConvertible<unique_ptr<_Up, _Ep>, _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(unique_ptr&& __u) _NOEXCEPT - : __ptr_(__u.release(), _VSTD::forward<deleter_type>(__u.get_deleter())) {} +#else // _LIBCPP_CXX03_LANG +private: + template <class _Up> explicit unique_ptr(_Up); - _LIBCPP_INLINE_VISIBILITY unique_ptr& operator=(unique_ptr&& __u) _NOEXCEPT - { - reset(__u.release()); - __ptr_.second() = _VSTD::forward<deleter_type>(__u.get_deleter()); - return *this; - } + unique_ptr(unique_ptr&); + template <class _Up> unique_ptr(unique_ptr<_Up>&); - template <class _Up, class _Ep> - _LIBCPP_INLINE_VISIBILITY - unique_ptr(unique_ptr<_Up, _Ep>&& __u, - typename enable_if - < - is_array<_Up>::value && - __same_or_less_cv_qualified<typename unique_ptr<_Up, _Ep>::pointer, pointer>::value - && is_convertible<_Ep, deleter_type>::value && - ( - !is_reference<deleter_type>::value || - is_same<deleter_type, _Ep>::value - ), - __nat - >::type = __nat() - ) _NOEXCEPT - : __ptr_(__u.release(), _VSTD::forward<deleter_type>(__u.get_deleter())) {} - - - template <class _Up, class _Ep> - _LIBCPP_INLINE_VISIBILITY - typename enable_if - < - is_array<_Up>::value && - __same_or_less_cv_qualified<typename unique_ptr<_Up, _Ep>::pointer, pointer>::value && - is_assignable<deleter_type&, _Ep&&>::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 explicit unique_ptr(pointer __p) - : __ptr_(__p) - { - static_assert(!is_pointer<deleter_type>::value, - "unique_ptr constructed with null function pointer deleter"); - } + unique_ptr& operator=(unique_ptr&); + template <class _Up> unique_ptr& operator=(unique_ptr<_Up>&); - _LIBCPP_INLINE_VISIBILITY unique_ptr(pointer __p, deleter_type __d) - : __ptr_(__p, _VSTD::forward<deleter_type>(__d)) {} + template <class _Up> + unique_ptr(_Up __u, + typename conditional< + is_reference<deleter_type>::value, deleter_type, + typename add_lvalue_reference<const deleter_type>::type>::type, + typename enable_if<is_convertible<_Up, pointer>::value, + __nat>::type = __nat()); +public: + _LIBCPP_INLINE_VISIBILITY + unique_ptr() : __ptr_(pointer()) { + static_assert(!is_pointer<deleter_type>::value, + "unique_ptr constructed with null function pointer deleter"); + } + _LIBCPP_INLINE_VISIBILITY + unique_ptr(nullptr_t) : __ptr_(pointer()) { + static_assert(!is_pointer<deleter_type>::value, + "unique_ptr constructed with null function pointer deleter"); + } + + _LIBCPP_INLINE_VISIBILITY + explicit unique_ptr(pointer __p) : __ptr_(__p) { + static_assert(!is_pointer<deleter_type>::value, + "unique_ptr constructed with null function pointer deleter"); + } + + _LIBCPP_INLINE_VISIBILITY + unique_ptr(pointer __p, deleter_type __d) + : __ptr_(__p, _VSTD::forward<deleter_type>(__d)) {} + + _LIBCPP_INLINE_VISIBILITY + unique_ptr(nullptr_t, deleter_type __d) + : __ptr_(pointer(), _VSTD::forward<deleter_type>(__d)) {} + + _LIBCPP_INLINE_VISIBILITY + operator __rv<unique_ptr>() { + return __rv<unique_ptr>(*this); + } + + _LIBCPP_INLINE_VISIBILITY + unique_ptr(__rv<unique_ptr> __u) + : __ptr_(__u->release(), + _VSTD::forward<deleter_type>(__u->get_deleter())) {} + + _LIBCPP_INLINE_VISIBILITY + unique_ptr& operator=(__rv<unique_ptr> __u) { + reset(__u->release()); + __ptr_.second() = _VSTD::forward<deleter_type>(__u->get_deleter()); + return *this; + } - _LIBCPP_INLINE_VISIBILITY unique_ptr(nullptr_t, deleter_type __d) - : __ptr_(pointer(), _VSTD::forward<deleter_type>(__d)) {} +#endif // _LIBCPP_CXX03_LANG - _LIBCPP_INLINE_VISIBILITY operator __rv<unique_ptr>() - { - return __rv<unique_ptr>(*this); - } - - _LIBCPP_INLINE_VISIBILITY unique_ptr(__rv<unique_ptr> __u) - : __ptr_(__u->release(), _VSTD::forward<deleter_type>(__u->get_deleter())) {} - - _LIBCPP_INLINE_VISIBILITY unique_ptr& operator=(__rv<unique_ptr> __u) - { - reset(__u->release()); - __ptr_.second() = _VSTD::forward<deleter_type>(__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 <class _Pp> - _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); - } +public: + _LIBCPP_INLINE_VISIBILITY + ~unique_ptr() { reset(); } - _LIBCPP_INLINE_VISIBILITY void swap(unique_ptr& __u) {__ptr_.swap(__u.__ptr_);} -private: + _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 <class _Pp> + _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 <class _Up> - explicit unique_ptr(_Up); - template <class _Up> - unique_ptr(_Up __u, - typename conditional< - is_reference<deleter_type>::value, - deleter_type, - typename add_lvalue_reference<const deleter_type>::type>::type, - typename enable_if - < - is_convertible<_Up, pointer>::value, - __nat - >::type = __nat()); -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES }; template <class _Tp, class _Dp> Modified: libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move.pass.cpp?rev=300406&r1=300405&r2=300406&view=diff ============================================================================== --- libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move.pass.cpp (original) +++ libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move.pass.cpp Sat Apr 15 20:51:04 2017 @@ -82,31 +82,32 @@ void test_sfinae() { static_assert(!std::is_assignable<U, U&>::value, ""); static_assert(!std::is_assignable<U, const U&>::value, ""); static_assert(!std::is_assignable<U, const U&&>::value, ""); - static_assert(std::is_assignable<U, U&&>::value, ""); + static_assert(std::is_nothrow_assignable<U, U&&>::value, ""); } { typedef std::unique_ptr<VT, GenericDeleter> U; static_assert(!std::is_assignable<U, U&>::value, ""); static_assert(!std::is_assignable<U, const U&>::value, ""); static_assert(!std::is_assignable<U, const U&&>::value, ""); - static_assert(std::is_assignable<U, U&&>::value, ""); + static_assert(std::is_nothrow_assignable<U, U&&>::value, ""); } { typedef std::unique_ptr<VT, NCDeleter<VT>&> U; static_assert(!std::is_assignable<U, U&>::value, ""); static_assert(!std::is_assignable<U, const U&>::value, ""); static_assert(!std::is_assignable<U, const U&&>::value, ""); - static_assert(std::is_assignable<U, U&&>::value, ""); + static_assert(std::is_nothrow_assignable<U, U&&>::value, ""); } { typedef std::unique_ptr<VT, const NCDeleter<VT>&> U; static_assert(!std::is_assignable<U, U&>::value, ""); static_assert(!std::is_assignable<U, const U&>::value, ""); static_assert(!std::is_assignable<U, const U&&>::value, ""); - static_assert(std::is_assignable<U, U&&>::value, ""); + static_assert(std::is_nothrow_assignable<U, U&&>::value, ""); } } + int main() { { test_basic</*IsArray*/ false>(); Added: libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.pass.cpp?rev=300406&view=auto ============================================================================== --- libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.pass.cpp (added) +++ libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.pass.cpp Sat Apr 15 20:51:04 2017 @@ -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 + +// <memory> + +// unique_ptr + +// Test unique_ptr converting move ctor + +#include <memory> +#include <cassert> + +#include "test_macros.h" +#include "unique_ptr_test_helper.h" +#include "type_id.h" + +template <int ID = 0> +struct GenericDeleter { + void operator()(void*) const {} +}; + +template <int ID = 0> +struct GenericConvertingDeleter { + + template <int OID> + GenericConvertingDeleter(GenericConvertingDeleter<OID>) {} + + template <int OID> + GenericConvertingDeleter& operator=(GenericConvertingDeleter<OID> const&) { + return *this; + } + + void operator()(void*) const {} +}; + +template <class T, class U> +using EnableIfNotSame = typename std::enable_if< + !std::is_same<typename std::decay<T>::type, typename std::decay<U>::type>::value +>::type; + +template <template <int> class Templ, class Other> +struct is_specialization : std::false_type {}; + +template <template <int> class Templ, int ID> +struct is_specialization<Templ, Templ<ID> > : std::true_type {}; + +template <template <int> class Templ, class Other> +using EnableIfSpecialization = typename std::enable_if< + is_specialization<Templ, typename std::decay<Other>::type >::value + >::type; + +template <int ID> +struct TrackingDeleter { + TrackingDeleter() : arg_type(&makeArgumentID<>()) {} + + TrackingDeleter(TrackingDeleter const&) + : arg_type(&makeArgumentID<TrackingDeleter const&>()) {} + + TrackingDeleter(TrackingDeleter&&) + : arg_type(&makeArgumentID<TrackingDeleter &&>()) {} + + template <class T, class = EnableIfSpecialization<TrackingDeleter, T> > + TrackingDeleter(T&&) : arg_type(&makeArgumentID<T&&>()) {} + + TrackingDeleter& operator=(TrackingDeleter const&) { + arg_type = &makeArgumentID<TrackingDeleter const&>(); + return *this; + } + + TrackingDeleter& operator=(TrackingDeleter &&) { + arg_type = &makeArgumentID<TrackingDeleter &&>(); + return *this; + } + + template <class T, class = EnableIfSpecialization<TrackingDeleter, T> > + TrackingDeleter& operator=(T&&) { + arg_type = &makeArgumentID<T&&>(); + return *this; + } + + void operator()(void*) const {} + +public: + TypeID const* reset() const { + TypeID const* tmp = arg_type; + arg_type = nullptr; + return tmp; + } + + mutable TypeID const* arg_type; +}; + +template <int ID> +struct ConstTrackingDeleter { + ConstTrackingDeleter() : arg_type(&makeArgumentID<>()) {} + + ConstTrackingDeleter(ConstTrackingDeleter const&) + : arg_type(&makeArgumentID<ConstTrackingDeleter const&>()) {} + + ConstTrackingDeleter(ConstTrackingDeleter&&) + : arg_type(&makeArgumentID<ConstTrackingDeleter &&>()) {} + + template <class T, class = EnableIfSpecialization<ConstTrackingDeleter, T> > + ConstTrackingDeleter(T&&) : arg_type(&makeArgumentID<T&&>()) {} + + const ConstTrackingDeleter& operator=(ConstTrackingDeleter const&) const { + arg_type = &makeArgumentID<ConstTrackingDeleter const&>(); + return *this; + } + + const ConstTrackingDeleter& operator=(ConstTrackingDeleter &&) const { + arg_type = &makeArgumentID<ConstTrackingDeleter &&>(); + return *this; + } + + template <class T, class = EnableIfSpecialization<ConstTrackingDeleter, T> > + const ConstTrackingDeleter& operator=(T&&) const { + arg_type = &makeArgumentID<T&&>(); + return *this; + } + + void operator()(void*) const {} + +public: + TypeID const* reset() const { + TypeID const* tmp = arg_type; + arg_type = nullptr; + return tmp; + } + + mutable TypeID const* arg_type; +}; + +template <class ExpectT, int ID> +bool checkArg(TrackingDeleter<ID> const& d) { + return d.arg_type && *d.arg_type == makeArgumentID<ExpectT>(); +} + +template <class ExpectT, int ID> +bool checkArg(ConstTrackingDeleter<ID> const& d) { + return d.arg_type && *d.arg_type == makeArgumentID<ExpectT>(); +} + +template <class From, bool AssignIsConst = false> +struct AssignDeleter { + AssignDeleter() = default; + AssignDeleter(AssignDeleter const&) = default; + AssignDeleter(AssignDeleter&&) = default; + + AssignDeleter& operator=(AssignDeleter const&) = delete; + AssignDeleter& operator=(AssignDeleter &&) = delete; + + template <class T> AssignDeleter& operator=(T&&) && = delete; + template <class T> AssignDeleter& operator=(T&&) const && = delete; + + template <class T, class = typename std::enable_if< + std::is_same<T&&, From>::value && !AssignIsConst + >::type> + AssignDeleter& operator=(T&&) & { return *this; } + + template <class T, class = typename std::enable_if< + std::is_same<T&&, From>::value && AssignIsConst + >::type> + const AssignDeleter& operator=(T&&) const & { return *this; } + + template <class T> + void operator()(T) const {} +}; + +template <class VT, class DDest, class DSource> + void doDeleterTest() { + using U1 = std::unique_ptr<VT, DDest>; + using U2 = std::unique_ptr<VT, DSource>; + static_assert(std::is_nothrow_assignable<U1, U2&&>::value, ""); + typename std::decay<DDest>::type ddest; + typename std::decay<DSource>::type dsource; + U1 u1(nullptr, ddest); + U2 u2(nullptr, dsource); + u1 = std::move(u2); +} + +template <bool IsArray> +void test_sfinae() { + typedef typename std::conditional<IsArray, A[], A>::type VT; + + { // Test that different non-reference deleter types are allowed so long + // as they convert to each other. + using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> >; + using U2 = std::unique_ptr<VT, GenericConvertingDeleter<1> >; + static_assert(std::is_assignable<U1, U2&&>::value, ""); + } + { // Test that different non-reference deleter types are disallowed when + // they cannot convert. + using U1 = std::unique_ptr<VT, GenericDeleter<0> >; + using U2 = std::unique_ptr<VT, GenericDeleter<1> >; + static_assert(!std::is_assignable<U1, U2&&>::value, ""); + } + { // Test that if the deleter assignment is not valid the assignment operator + // SFINAEs. + using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> const& >; + using U2 = std::unique_ptr<VT, GenericConvertingDeleter<0> >; + using U3 = std::unique_ptr<VT, GenericConvertingDeleter<0> &>; + using U4 = std::unique_ptr<VT, GenericConvertingDeleter<1> >; + using U5 = std::unique_ptr<VT, GenericConvertingDeleter<1> const&>; + static_assert(!std::is_assignable<U1, U2&&>::value, ""); + static_assert(!std::is_assignable<U1, U3&&>::value, ""); + static_assert(!std::is_assignable<U1, U4&&>::value, ""); + static_assert(!std::is_assignable<U1, U5&&>::value, ""); + + using U1C = std::unique_ptr<const VT, GenericConvertingDeleter<0> const&>; + static_assert(std::is_nothrow_assignable<U1C, U1&&>::value, ""); + } + { // Test that if the deleter assignment is not valid the assignment operator + // SFINAEs. + using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> & >; + using U2 = std::unique_ptr<VT, GenericConvertingDeleter<0> >; + using U3 = std::unique_ptr<VT, GenericConvertingDeleter<0> &>; + using U4 = std::unique_ptr<VT, GenericConvertingDeleter<1> >; + using U5 = std::unique_ptr<VT, GenericConvertingDeleter<1> const&>; + + static_assert(std::is_nothrow_assignable<U1, U2&&>::value, ""); + static_assert(std::is_nothrow_assignable<U1, U3&&>::value, ""); + static_assert(std::is_nothrow_assignable<U1, U4&&>::value, ""); + static_assert(std::is_nothrow_assignable<U1, U5&&>::value, ""); + + using U1C = std::unique_ptr<const VT, GenericConvertingDeleter<0> &>; + static_assert(std::is_nothrow_assignable<U1C, U1&&>::value, ""); + } + { // Test that non-reference destination deleters can be assigned + // from any source deleter type with a sutible conversion. Including + // reference types. + using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> >; + using U2 = std::unique_ptr<VT, GenericConvertingDeleter<0> &>; + using U3 = std::unique_ptr<VT, GenericConvertingDeleter<0> const &>; + using U4 = std::unique_ptr<VT, GenericConvertingDeleter<1> >; + using U5 = std::unique_ptr<VT, GenericConvertingDeleter<1> &>; + using U6 = std::unique_ptr<VT, GenericConvertingDeleter<1> const&>; + static_assert(std::is_assignable<U1, U2&&>::value, ""); + static_assert(std::is_assignable<U1, U3&&>::value, ""); + static_assert(std::is_assignable<U1, U4&&>::value, ""); + static_assert(std::is_assignable<U1, U5&&>::value, ""); + static_assert(std::is_assignable<U1, U6&&>::value, ""); + } + ///////////////////////////////////////////////////////////////////////////// + { + using Del = GenericDeleter<0>; + using AD = AssignDeleter<Del&&>; + using ADC = AssignDeleter<Del&&, /*AllowConstAssign*/true>; + doDeleterTest<VT, AD, Del>(); + doDeleterTest<VT, AD&, Del>(); + doDeleterTest<VT, ADC const&, Del>(); + } + { + using Del = GenericDeleter<0>; + using AD = AssignDeleter<Del&>; + using ADC = AssignDeleter<Del&, /*AllowConstAssign*/true>; + doDeleterTest<VT, AD, Del&>(); + doDeleterTest<VT, AD&, Del&>(); + doDeleterTest<VT, ADC const&, Del&>(); + } + { + using Del = GenericDeleter<0>; + using AD = AssignDeleter<Del const&>; + using ADC = AssignDeleter<Del const&, /*AllowConstAssign*/true>; + doDeleterTest<VT, AD, Del const&>(); + doDeleterTest<VT, AD&, Del const&>(); + doDeleterTest<VT, ADC const&, Del const&>(); + } +} + + +template <bool IsArray> +void test_noexcept() { + typedef typename std::conditional<IsArray, A[], A>::type VT; + { + typedef std::unique_ptr<const VT> APtr; + typedef std::unique_ptr<VT> BPtr; + static_assert(std::is_nothrow_assignable<APtr, BPtr>::value, ""); + } + { + typedef std::unique_ptr<const VT, CDeleter<const VT> > APtr; + typedef std::unique_ptr<VT, CDeleter<VT> > BPtr; + static_assert(std::is_nothrow_assignable<APtr, BPtr>::value, ""); + } + { + typedef std::unique_ptr<const VT, NCDeleter<const VT>&> APtr; + typedef std::unique_ptr<VT, NCDeleter<const VT>&> BPtr; + static_assert(std::is_nothrow_assignable<APtr, BPtr>::value, ""); + } + { + typedef std::unique_ptr<const VT, const NCConstDeleter<const VT>&> APtr; + typedef std::unique_ptr<VT, const NCConstDeleter<const VT>&> BPtr; + static_assert(std::is_nothrow_assignable<APtr, BPtr>::value, ""); + } +} + +template <bool IsArray> +void test_deleter_value_category() { + typedef typename std::conditional<IsArray, A[], A>::type VT; + using TD1 = TrackingDeleter<1>; + using TD2 = TrackingDeleter<2>; + TD1 d1; + TD2 d2; + using CD1 = ConstTrackingDeleter<1>; + using CD2 = ConstTrackingDeleter<2>; + CD1 cd1; + CD2 cd2; + + { // Test non-reference deleter conversions + using U1 = std::unique_ptr<VT, TD1 >; + using U2 = std::unique_ptr<VT, TD2 >; + U1 u1; + U2 u2; + u1.get_deleter().reset(); + u1 = std::move(u2); + assert(checkArg<TD2&&>(u1.get_deleter())); + } + { // Test assignment to non-const ref + using U1 = std::unique_ptr<VT, TD1& >; + using U2 = std::unique_ptr<VT, TD2 >; + U1 u1(nullptr, d1); + U2 u2; + u1.get_deleter().reset(); + u1 = std::move(u2); + assert(checkArg<TD2&&>(u1.get_deleter())); + } + { // Test assignment to const&. + using U1 = std::unique_ptr<VT, CD1 const& >; + using U2 = std::unique_ptr<VT, CD2 >; + U1 u1(nullptr, cd1); + U2 u2; + u1.get_deleter().reset(); + u1 = std::move(u2); + assert(checkArg<CD2&&>(u1.get_deleter())); + } + + { // Test assignment from non-const ref + using U1 = std::unique_ptr<VT, TD1 >; + using U2 = std::unique_ptr<VT, TD2& >; + U1 u1; + U2 u2(nullptr, d2); + u1.get_deleter().reset(); + u1 = std::move(u2); + assert(checkArg<TD2&>(u1.get_deleter())); + } + { // Test assignment from const ref + using U1 = std::unique_ptr<VT, TD1 >; + using U2 = std::unique_ptr<VT, TD2 const& >; + U1 u1; + U2 u2(nullptr, d2); + u1.get_deleter().reset(); + u1 = std::move(u2); + assert(checkArg<TD2 const&>(u1.get_deleter())); + } + + { // Test assignment from non-const ref + using U1 = std::unique_ptr<VT, TD1& >; + using U2 = std::unique_ptr<VT, TD2& >; + U1 u1(nullptr, d1); + U2 u2(nullptr, d2); + u1.get_deleter().reset(); + u1 = std::move(u2); + assert(checkArg<TD2&>(u1.get_deleter())); + } + { // Test assignment from const ref + using U1 = std::unique_ptr<VT, TD1& >; + using U2 = std::unique_ptr<VT, TD2 const& >; + U1 u1(nullptr, d1); + U2 u2(nullptr, d2); + u1.get_deleter().reset(); + u1 = std::move(u2); + assert(checkArg<TD2 const&>(u1.get_deleter())); + } + + { // Test assignment from non-const ref + using U1 = std::unique_ptr<VT, CD1 const& >; + using U2 = std::unique_ptr<VT, CD2 & >; + U1 u1(nullptr, cd1); + U2 u2(nullptr, cd2); + u1.get_deleter().reset(); + u1 = std::move(u2); + assert(checkArg<CD2 &>(u1.get_deleter())); + } + { // Test assignment from const ref + using U1 = std::unique_ptr<VT, CD1 const& >; + using U2 = std::unique_ptr<VT, CD2 const& >; + U1 u1(nullptr, cd1); + U2 u2(nullptr, cd2); + u1.get_deleter().reset(); + u1 = std::move(u2); + assert(checkArg<CD2 const&>(u1.get_deleter())); + } +} + +int main() { + { + test_sfinae</*IsArray*/false>(); + test_noexcept<false>(); + test_deleter_value_category<false>(); + } + { + test_sfinae</*IsArray*/true>(); + test_noexcept<true>(); + test_deleter_value_category<true>(); + } +} Modified: libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/default.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/default.pass.cpp?rev=300406&r1=300405&r2=300406&view=diff ============================================================================== --- libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/default.pass.cpp (original) +++ libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/default.pass.cpp Sat Apr 15 20:51:04 2017 @@ -31,8 +31,6 @@ #include "deleter_types.h" #include "unique_ptr_test_helper.h" -#include "test_workarounds.h" // For TEST_WORKAROUND_UPCOMING_UNIQUE_PTR_CHANGES - #if defined(_LIBCPP_VERSION) && TEST_STD_VER >= 11 _LIBCPP_SAFE_STATIC std::unique_ptr<int> global_static_unique_ptr_single; _LIBCPP_SAFE_STATIC std::unique_ptr<int[]> global_static_unique_ptr_runtime; @@ -47,7 +45,7 @@ struct NonDefaultDeleter { template <class ElemType> void test_sfinae() { -#if TEST_STD_VER >= 11 && !defined(TEST_WORKAROUND_UPCOMING_UNIQUE_PTR_CHANGES) +#if TEST_STD_VER >= 11 { // the constructor does not participate in overload resultion when // the deleter is a pointer type using U = std::unique_ptr<ElemType, void (*)(void*)>; Modified: libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move.pass.cpp?rev=300406&r1=300405&r2=300406&view=diff ============================================================================== --- libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move.pass.cpp (original) +++ libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move.pass.cpp Sat Apr 15 20:51:04 2017 @@ -18,7 +18,6 @@ #include <cassert> #include "test_macros.h" -#include "deleter_types.h" #include "unique_ptr_test_helper.h" //============================================================================= @@ -139,13 +138,37 @@ void test_basic() { assert(A::count == 0); } +template <class VT> +void test_noexcept() { +#if TEST_STD_VER >= 11 + { + typedef std::unique_ptr<VT> U; + static_assert(std::is_nothrow_move_constructible<U>::value, ""); + } + { + typedef std::unique_ptr<VT, Deleter<VT> > U; + static_assert(std::is_nothrow_move_constructible<U>::value, ""); + } + { + typedef std::unique_ptr<VT, NCDeleter<VT> &> U; + static_assert(std::is_nothrow_move_constructible<U>::value, ""); + } + { + typedef std::unique_ptr<VT, const NCConstDeleter<VT> &> U; + static_assert(std::is_nothrow_move_constructible<U>::value, ""); + } +#endif +} + int main() { { test_basic</*IsArray*/ false>(); test_sfinae<int>(); + test_noexcept<int>(); } { test_basic</*IsArray*/ true>(); test_sfinae<int[]>(); + test_noexcept<int[]>(); } } Added: libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.pass.cpp?rev=300406&view=auto ============================================================================== --- libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.pass.cpp (added) +++ libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.pass.cpp Sat Apr 15 20:51:04 2017 @@ -0,0 +1,124 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <memory> + +// unique_ptr + +// Test unique_ptr converting move ctor + +#include <memory> +#include <cassert> + +#include "test_macros.h" +#include "unique_ptr_test_helper.h" + +template <int ID = 0> +struct GenericDeleter { + void operator()(void*) const {} +}; + +template <int ID = 0> +struct GenericConvertingDeleter { + template <int OID> + GenericConvertingDeleter(GenericConvertingDeleter<OID>) {} + void operator()(void*) const {} +}; + +template <bool IsArray> +void test_sfinae() { +#if TEST_STD_VER >= 11 + typedef typename std::conditional<IsArray, A[], A>::type VT; + + { // Test that different non-reference deleter types are allowed so long + // as they convert to each other. + using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> >; + using U2 = std::unique_ptr<VT, GenericConvertingDeleter<1> >; + static_assert(std::is_constructible<U1, U2&&>::value, ""); + } + { // Test that different non-reference deleter types are disallowed when + // they cannot convert. + using U1 = std::unique_ptr<VT, GenericDeleter<0> >; + using U2 = std::unique_ptr<VT, GenericDeleter<1> >; + static_assert(!std::is_constructible<U1, U2&&>::value, ""); + } + { // Test that if the destination deleter is a reference type then only + // exact matches are allowed. + using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> const& >; + using U2 = std::unique_ptr<VT, GenericConvertingDeleter<0> >; + using U3 = std::unique_ptr<VT, GenericConvertingDeleter<0> &>; + using U4 = std::unique_ptr<VT, GenericConvertingDeleter<1> >; + using U5 = std::unique_ptr<VT, GenericConvertingDeleter<1> const&>; + static_assert(!std::is_constructible<U1, U2&&>::value, ""); + static_assert(!std::is_constructible<U1, U3&&>::value, ""); + static_assert(!std::is_constructible<U1, U4&&>::value, ""); + static_assert(!std::is_constructible<U1, U5&&>::value, ""); + + using U1C = std::unique_ptr<const VT, GenericConvertingDeleter<0> const&>; + static_assert(std::is_nothrow_constructible<U1C, U1&&>::value, ""); + } + { // Test that non-reference destination deleters can be constructed + // from any source deleter type with a sutible conversion. Including + // reference types. + using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> >; + using U2 = std::unique_ptr<VT, GenericConvertingDeleter<0> &>; + using U3 = std::unique_ptr<VT, GenericConvertingDeleter<0> const &>; + using U4 = std::unique_ptr<VT, GenericConvertingDeleter<1> >; + using U5 = std::unique_ptr<VT, GenericConvertingDeleter<1> &>; + using U6 = std::unique_ptr<VT, GenericConvertingDeleter<1> const&>; + static_assert(std::is_constructible<U1, U2&&>::value, ""); + static_assert(std::is_constructible<U1, U3&&>::value, ""); + static_assert(std::is_constructible<U1, U4&&>::value, ""); + static_assert(std::is_constructible<U1, U5&&>::value, ""); + static_assert(std::is_constructible<U1, U6&&>::value, ""); + } +#endif +} + + +template <bool IsArray> +void test_noexcept() { +#if TEST_STD_VER >= 11 + typedef typename std::conditional<IsArray, A[], A>::type VT; + { + typedef std::unique_ptr<const VT> APtr; + typedef std::unique_ptr<VT> BPtr; + static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, ""); + } + { + typedef std::unique_ptr<const VT, CDeleter<const VT> > APtr; + typedef std::unique_ptr<VT, CDeleter<VT> > BPtr; + static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, ""); + } + { + typedef std::unique_ptr<const VT, NCDeleter<const VT>&> APtr; + typedef std::unique_ptr<VT, NCDeleter<const VT>&> BPtr; + static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, ""); + } + { + typedef std::unique_ptr<const VT, const NCConstDeleter<const VT>&> APtr; + typedef std::unique_ptr<VT, const NCConstDeleter<const VT>&> BPtr; + static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, ""); + } +#endif +} + + +int main() { + { + test_sfinae</*IsArray*/false>(); + test_noexcept<false>(); + } + { + test_sfinae</*IsArray*/true>(); + test_noexcept<true>(); + } +} Modified: libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.runtime.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.runtime.pass.cpp?rev=300406&r1=300405&r2=300406&view=diff ============================================================================== --- libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.runtime.pass.cpp (original) +++ libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.runtime.pass.cpp Sat Apr 15 20:51:04 2017 @@ -77,4 +77,7 @@ void test_sfinae() { } } -int main() { test_sfinae(); } + +int main() { + test_sfinae(); +} Modified: libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.single.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.single.pass.cpp?rev=300406&r1=300405&r2=300406&view=diff ============================================================================== --- libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.single.pass.cpp (original) +++ libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.single.pass.cpp Sat Apr 15 20:51:04 2017 @@ -22,7 +22,7 @@ #include <utility> #include <cassert> -#include "deleter_types.h" +#include "test_macros.h" #include "unique_ptr_test_helper.h" // test converting move ctor. Should only require a MoveConstructible deleter, or if @@ -135,8 +135,35 @@ void test_sfinae() { } } +void test_noexcept() { + { + typedef std::unique_ptr<A> APtr; + typedef std::unique_ptr<B> BPtr; + static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, ""); + } + { + typedef std::unique_ptr<A, Deleter<A> > APtr; + typedef std::unique_ptr<B, Deleter<B> > BPtr; + static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, ""); + } + { + typedef std::unique_ptr<A, NCDeleter<A>&> APtr; + typedef std::unique_ptr<B, NCDeleter<A>&> BPtr; + static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, ""); + } + { + typedef std::unique_ptr<A, const NCConstDeleter<A>&> APtr; + typedef std::unique_ptr<B, const NCConstDeleter<A>&> BPtr; + static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, ""); + } +} + int main() { { + test_sfinae(); + test_noexcept(); + } + { typedef std::unique_ptr<A> APtr; typedef std::unique_ptr<B> BPtr; { // explicit @@ -218,5 +245,4 @@ int main() { } checkNoneAlive(); } - test_sfinae(); } Modified: libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/nullptr.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/nullptr.pass.cpp?rev=300406&r1=300405&r2=300406&view=diff ============================================================================== --- libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/nullptr.pass.cpp (original) +++ libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/nullptr.pass.cpp Sat Apr 15 20:51:04 2017 @@ -17,25 +17,14 @@ #include <cassert> #include "test_macros.h" -#include "deleter_types.h" #include "unique_ptr_test_helper.h" -#include "test_workarounds.h" // For TEST_WORKAROUND_UPCOMING_UNIQUE_PTR_CHANGES -// default unique_ptr ctor should only require default Deleter ctor -class DefaultDeleter { - int state_; - - DefaultDeleter(DefaultDeleter&); - DefaultDeleter& operator=(DefaultDeleter&); - -public: - DefaultDeleter() : state_(5) {} - - int state() const { return state_; } +#if defined(_LIBCPP_VERSION) && TEST_STD_VER >= 11 +_LIBCPP_SAFE_STATIC std::unique_ptr<int> global_static_unique_ptr_single(nullptr); +_LIBCPP_SAFE_STATIC std::unique_ptr<int[]> global_static_unique_ptr_runtime(nullptr); +#endif - void operator()(void*) {} -}; #if TEST_STD_VER >= 11 struct NonDefaultDeleter { @@ -46,15 +35,6 @@ struct NonDefaultDeleter { template <class VT> void test_basic() { - { - std::unique_ptr<VT> p(nullptr); - assert(p.get() == 0); - } - { - std::unique_ptr<VT, DefaultDeleter> p(nullptr); - assert(p.get() == 0); - assert(p.get_deleter().state() == 5); - } #if TEST_STD_VER >= 11 { using U1 = std::unique_ptr<VT>; @@ -65,11 +45,20 @@ void test_basic() { ""); } #endif + { + std::unique_ptr<VT> p(nullptr); + assert(p.get() == 0); + } + { + std::unique_ptr<VT, NCDeleter<VT> > p(nullptr); + assert(p.get() == 0); + assert(p.get_deleter().state() == 0); + } } template <class VT> void test_sfinae() { -#if TEST_STD_VER >= 11 && !defined(TEST_WORKAROUND_UPCOMING_UNIQUE_PTR_CHANGES) +#if TEST_STD_VER >= 11 { // the constructor does not participate in overload resultion when // the deleter is a pointer type using U = std::unique_ptr<VT, void (*)(void*)>; Modified: libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer.pass.cpp?rev=300406&r1=300405&r2=300406&view=diff ============================================================================== --- libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer.pass.cpp (original) +++ libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer.pass.cpp Sat Apr 15 20:51:04 2017 @@ -35,8 +35,6 @@ #include "test_macros.h" #include "unique_ptr_test_helper.h" -#include "test_workarounds.h" // For TEST_WORKAROUND_UPCOMING_UNIQUE_PTR_CHANGES - // unique_ptr(pointer) ctor should only require default Deleter ctor template <bool IsArray> @@ -47,8 +45,14 @@ void test_pointer() { { using U1 = std::unique_ptr<ValueT>; using U2 = std::unique_ptr<ValueT, Deleter<ValueT> >; + + // Test for noexcept static_assert(std::is_nothrow_constructible<U1, A*>::value, ""); static_assert(std::is_nothrow_constructible<U2, A*>::value, ""); + + // Test for explicit + static_assert(!std::is_convertible<A*, U1>::value, ""); + static_assert(!std::is_convertible<A*, U2>::value, ""); } #endif { @@ -103,7 +107,7 @@ struct GenericDeleter { template <class T> void test_sfinae() { -#if TEST_STD_VER >= 11 && !defined(TEST_WORKAROUND_UPCOMING_UNIQUE_PTR_CHANGES) +#if TEST_STD_VER >= 11 { // the constructor does not participate in overload resultion when // the deleter is a pointer type using U = std::unique_ptr<T, void (*)(void*)>; Modified: libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer_deleter.fail.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer_deleter.fail.cpp?rev=300406&r1=300405&r2=300406&view=diff ============================================================================== --- libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer_deleter.fail.cpp (original) +++ libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer_deleter.fail.cpp Sat Apr 15 20:51:04 2017 @@ -19,17 +19,11 @@ #include <memory> -#include "test_workarounds.h" - struct Deleter { void operator()(int* p) const { delete p; } }; int main() { -#if defined(TEST_WORKAROUND_UPCOMING_UNIQUE_PTR_CHANGES) -// expected-error@memory:* {{static_assert failed "rvalue deleter bound to reference"}} -#else -// expected-error@+2 {{call to deleted constructor of 'std::unique_ptr<int, const Deleter &>}} -#endif + // expected-error@+1 {{call to deleted constructor of 'std::unique_ptr<int, const Deleter &>}} std::unique_ptr<int, const Deleter&> s((int*)nullptr, Deleter()); } Modified: libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer_deleter.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer_deleter.pass.cpp?rev=300406&r1=300405&r2=300406&view=diff ============================================================================== --- libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer_deleter.pass.cpp (original) +++ libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer_deleter.pass.cpp Sat Apr 15 20:51:04 2017 @@ -29,8 +29,6 @@ #include "test_macros.h" #include "unique_ptr_test_helper.h" -#include "test_workarounds.h" // For TEST_WORKAROUND_UPCOMING_UNIQUE_PTR_CHANGES - bool my_free_called = false; void my_free(void*) { my_free_called = true; } @@ -56,7 +54,7 @@ struct NoCopyMoveDeleter : DeleterBase { template <bool IsArray> void test_sfinae() { -#if TEST_STD_VER >= 11 && !defined(TEST_WORKAROUND_UPCOMING_UNIQUE_PTR_CHANGES) +#if TEST_STD_VER >= 11 typedef typename std::conditional<!IsArray, int, int[]>::type VT; { using D = CopyOnlyDeleter; @@ -137,13 +135,13 @@ void test_noexcept() { } void test_sfinae_runtime() { -#if TEST_STD_VER >= 11 && !defined(TEST_WORKAROUND_UPCOMING_UNIQUE_PTR_CHANGES) +#if TEST_STD_VER >= 11 { using D = CopyOnlyDeleter; using U = std::unique_ptr<A[], D>; - static_assert(std::is_constructible<U, A*, D const&>::value, ""); - static_assert(std::is_constructible<U, A*, D&>::value, ""); - static_assert(std::is_constructible<U, A*, D&&>::value, ""); + static_assert(std::is_nothrow_constructible<U, A*, D const&>::value, ""); + static_assert(std::is_nothrow_constructible<U, A*, D&>::value, ""); + static_assert(std::is_nothrow_constructible<U, A*, D&&>::value, ""); static_assert(!std::is_constructible<U, B*, D const&>::value, ""); static_assert(!std::is_constructible<U, B*, D&>::value, ""); @@ -158,7 +156,7 @@ void test_sfinae_runtime() { using U = std::unique_ptr<A[], D>; static_assert(!std::is_constructible<U, A*, D const&>::value, ""); static_assert(!std::is_constructible<U, A*, D&>::value, ""); - static_assert(std::is_constructible<U, A*, D&&>::value, ""); + static_assert(std::is_nothrow_constructible<U, A*, D&&>::value, ""); static_assert(!std::is_constructible<U, B*, D const&>::value, ""); static_assert(!std::is_constructible<U, B*, D&>::value, ""); @@ -181,7 +179,7 @@ void test_sfinae_runtime() { using D = NoCopyMoveDeleter; using U = std::unique_ptr<A[], D&>; static_assert(!std::is_constructible<U, A*, D const&>::value, ""); - static_assert(std::is_constructible<U, A*, D&>::value, ""); + static_assert(std::is_nothrow_constructible<U, A*, D&>::value, ""); static_assert(!std::is_constructible<U, A*, D&&>::value, ""); static_assert(!std::is_constructible<U, A*, const D&&>::value, ""); @@ -193,8 +191,8 @@ void test_sfinae_runtime() { { using D = NoCopyMoveDeleter; using U = std::unique_ptr<A[], const D&>; - static_assert(std::is_constructible<U, A*, D const&>::value, ""); - static_assert(std::is_constructible<U, A*, D&>::value, ""); + static_assert(std::is_nothrow_constructible<U, A*, D const&>::value, ""); + static_assert(std::is_nothrow_constructible<U, A*, D&>::value, ""); static_assert(!std::is_constructible<U, A*, D&&>::value, ""); static_assert(!std::is_constructible<U, A*, const D&&>::value, ""); @@ -291,15 +289,38 @@ void test_basic_single() { } } +template <bool IsArray> +void test_nullptr() { +#if TEST_STD_VER >= 11 + typedef typename std::conditional<!IsArray, A, A[]>::type VT; + { + std::unique_ptr<VT, Deleter<VT> > u(nullptr, Deleter<VT>{}); + assert(u.get() == nullptr); + } + { + NCDeleter<VT> d; + std::unique_ptr<VT, NCDeleter<VT>& > u(nullptr, d); + assert(u.get() == nullptr); + } + { + NCConstDeleter<VT> d; + std::unique_ptr<VT, NCConstDeleter<VT> const& > u(nullptr, d); + assert(u.get() == nullptr); + } +#endif +} + int main() { { test_basic</*IsArray*/ false>(); + test_nullptr<false>(); test_basic_single(); test_sfinae<false>(); test_noexcept<false>(); } { test_basic</*IsArray*/ true>(); + test_nullptr<true>(); test_sfinae<true>(); test_sfinae_runtime(); test_noexcept<true>(); Modified: libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.dtor/null.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.dtor/null.pass.cpp?rev=300406&r1=300405&r2=300406&view=diff ============================================================================== --- libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.dtor/null.pass.cpp (original) +++ libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.dtor/null.pass.cpp Sat Apr 15 20:51:04 2017 @@ -35,8 +35,8 @@ void test_basic() { Deleter d; assert(d.state() == 0); { - std::unique_ptr<T, Deleter&> p(0, d); - assert(p.get() == 0); + std::unique_ptr<T, Deleter&> p(nullptr, d); + assert(p.get() == nullptr); assert(&p.get_deleter() == &d); } assert(d.state() == 0); Modified: libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.modifiers/release.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.modifiers/release.pass.cpp?rev=300406&r1=300405&r2=300406&view=diff ============================================================================== --- libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.modifiers/release.pass.cpp (original) +++ libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.modifiers/release.pass.cpp Sat Apr 15 20:51:04 2017 @@ -16,12 +16,20 @@ #include <memory> #include <cassert> +#include "test_macros.h" #include "unique_ptr_test_helper.h" template <bool IsArray> void test_basic() { typedef typename std::conditional<IsArray, A[], A>::type VT; const int expect_alive = IsArray ? 3 : 1; +#if TEST_STD_VER >= 11 + { + using U = std::unique_ptr<VT>; + U u; ((void)u); + ASSERT_NOEXCEPT(u.release()); + } +#endif { std::unique_ptr<VT> p(newValue<VT>(expect_alive)); assert(A::count == expect_alive); Modified: libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.modifiers/reset.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.modifiers/reset.pass.cpp?rev=300406&r1=300405&r2=300406&view=diff ============================================================================== --- libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.modifiers/reset.pass.cpp (original) +++ libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.modifiers/reset.pass.cpp Sat Apr 15 20:51:04 2017 @@ -16,36 +16,102 @@ #include <memory> #include <cassert> +#include "test_macros.h" #include "unique_ptr_test_helper.h" template <bool IsArray> -void test_basic() { +void test_reset_pointer() { typedef typename std::conditional<IsArray, A[], A>::type VT; const int expect_alive = IsArray ? 3 : 1; +#if TEST_STD_VER >= 11 + { + using U = std::unique_ptr<VT>; + U u; ((void)u); + ASSERT_NOEXCEPT(u.reset((A*)nullptr)); + } +#endif { std::unique_ptr<VT> p(newValue<VT>(expect_alive)); assert(A::count == expect_alive); A* i = p.get(); assert(i != nullptr); - p.reset(); - assert(A::count == 0); - assert(p.get() == 0); + A* new_value = newValue<VT>(expect_alive); + assert(A::count == (expect_alive * 2)); + p.reset(new_value); + assert(A::count == expect_alive); + assert(p.get() == new_value); } assert(A::count == 0); { - std::unique_ptr<VT> p(newValue<VT>(expect_alive)); + std::unique_ptr<const VT> p(newValue<const VT>(expect_alive)); assert(A::count == expect_alive); - A* i = p.get(); + const A* i = p.get(); assert(i != nullptr); A* new_value = newValue<VT>(expect_alive); assert(A::count == (expect_alive * 2)); p.reset(new_value); assert(A::count == expect_alive); + assert(p.get() == new_value); + } + assert(A::count == 0); +} + +template <bool IsArray> +void test_reset_nullptr() { + typedef typename std::conditional<IsArray, A[], A>::type VT; + const int expect_alive = IsArray ? 3 : 1; +#if TEST_STD_VER >= 11 + { + using U = std::unique_ptr<VT>; + U u; ((void)u); + ASSERT_NOEXCEPT(u.reset(nullptr)); + } +#endif + { + std::unique_ptr<VT> p(newValue<VT>(expect_alive)); + assert(A::count == expect_alive); + A* i = p.get(); + assert(i != nullptr); + p.reset(nullptr); + assert(A::count == 0); + assert(p.get() == nullptr); + } + assert(A::count == 0); +} + + +template <bool IsArray> +void test_reset_no_arg() { + typedef typename std::conditional<IsArray, A[], A>::type VT; + const int expect_alive = IsArray ? 3 : 1; +#if TEST_STD_VER >= 11 + { + using U = std::unique_ptr<VT>; + U u; ((void)u); + ASSERT_NOEXCEPT(u.reset()); + } +#endif + { + std::unique_ptr<VT> p(newValue<VT>(expect_alive)); + assert(A::count == expect_alive); + A* i = p.get(); + assert(i != nullptr); + p.reset(); + assert(A::count == 0); + assert(p.get() == nullptr); } assert(A::count == 0); } int main() { - test_basic</*IsArray*/ false>(); - test_basic<true>(); + { + test_reset_pointer</*IsArray*/ false>(); + test_reset_nullptr<false>(); + test_reset_no_arg<false>(); + } + { + test_reset_pointer</*IsArray*/true>(); + test_reset_nullptr<true>(); + test_reset_no_arg<true>(); + } } Modified: libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.modifiers/swap.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.modifiers/swap.pass.cpp?rev=300406&r1=300405&r2=300406&view=diff ============================================================================== --- libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.modifiers/swap.pass.cpp (original) +++ libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.modifiers/swap.pass.cpp Sat Apr 15 20:51:04 2017 @@ -16,6 +16,7 @@ #include <memory> #include <cassert> +#include "test_macros.h" #include "unique_ptr_test_helper.h" struct TT { @@ -51,6 +52,13 @@ template <bool IsArray> void test_basic() { typedef typename std::conditional<IsArray, TT[], TT>::type VT; const int expect_alive = IsArray ? 5 : 1; +#if TEST_STD_VER >= 11 + { + using U = std::unique_ptr<VT, Deleter<VT> >; + U u; ((void)u); + ASSERT_NOEXCEPT(u.swap(u)); + } +#endif { TT* p1 = newValueInit<VT>(expect_alive, 1); std::unique_ptr<VT, Deleter<VT> > s1(p1, Deleter<VT>(1)); Modified: libcxx/trunk/test/support/deleter_types.h URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/support/deleter_types.h?rev=300406&r1=300405&r2=300406&view=diff ============================================================================== --- libcxx/trunk/test/support/deleter_types.h (original) +++ libcxx/trunk/test/support/deleter_types.h Sat Apr 15 20:51:04 2017 @@ -193,6 +193,10 @@ public: CDeleter() : state_(0) {} explicit CDeleter(int s) : state_(s) {} + template <class U> + CDeleter(const CDeleter<U>& d) + : state_(d.state()) {} + ~CDeleter() {assert(state_ >= 0); state_ = -1;} int state() const {return state_;} Modified: libcxx/trunk/test/support/test_workarounds.h URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/support/test_workarounds.h?rev=300406&r1=300405&r2=300406&view=diff ============================================================================== --- libcxx/trunk/test/support/test_workarounds.h (original) +++ libcxx/trunk/test/support/test_workarounds.h Sat Apr 15 20:51:04 2017 @@ -17,12 +17,4 @@ # define TEST_WORKAROUND_C1XX_BROKEN_NULLPTR_CONVERSION_OPERATOR #endif -// FIXME(EricWF): Remove this. This macro guards tests for upcoming changes -// and fixes to unique_ptr. Until the changes have been implemented in trunk -// the tests have to be disabled. However the tests have been left in until -// then so they can be used by other standard libraries. -#if defined(_LIBCPP_VERSION) -# define TEST_WORKAROUND_UPCOMING_UNIQUE_PTR_CHANGES -#endif - #endif // SUPPORT_TEST_WORKAROUNDS_H Modified: libcxx/trunk/www/cxx1z_status.html URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/www/cxx1z_status.html?rev=300406&r1=300405&r2=300406&view=diff ============================================================================== --- libcxx/trunk/www/cxx1z_status.html (original) +++ libcxx/trunk/www/cxx1z_status.html Sat Apr 15 20:51:04 2017 @@ -448,7 +448,7 @@ <tr><td><a href="http://wg21.link/LWG2794">2794</a></td><td>Missing requirements for allocator pointers</td><td>Kona</td><td></td></tr> <tr><td><a href="http://wg21.link/LWG2795">2795</a></td><td>§[global.functions] provides incorrect example of ADL use</td><td>Kona</td><td>Complete</td></tr> <tr><td><a href="http://wg21.link/LWG2796">2796</a></td><td>tuple should be a literal type</td><td>Kona</td><td></td></tr> - <tr><td><a href="http://wg21.link/LWG2801">2801</a></td><td>Default-constructibility of unique_ptr</td><td>Kona</td><td></td></tr> + <tr><td><a href="http://wg21.link/LWG2801">2801</a></td><td>Default-constructibility of unique_ptr</td><td>Kona</td><td>Complete</td></tr> <tr><td><a href="http://wg21.link/LWG2802">2802</a></td><td>shared_ptr constructor requirements for a deleter</td><td>Kona</td><td></td></tr> <tr><td><a href="http://wg21.link/LWG2804">2804</a></td><td>Unconditional constexpr default constructor for istream_iterator</td><td>Kona</td><td>Complete</td></tr> <tr><td><a href="http://wg21.link/LWG2806">2806</a></td><td>Base class of bad_optional_access</td><td>Kona</td><td>Complete</td></tr> @@ -478,7 +478,7 @@ <tr><td><a href="http://wg21.link/LWG2900">2900</a></td><td>The copy and move constructors of optional are not constexpr</td><td>Kona</td><td></td></tr> <tr><td><a href="http://wg21.link/LWG2903">2903</a></td><td>The form of initialization for the emplace-constructors is not specified</td><td>Kona</td><td></td></tr> <tr><td><a href="http://wg21.link/LWG2904">2904</a></td><td>Make variant move-assignment more exception safe</td><td>Kona</td><td></td></tr> - <tr><td><a href="http://wg21.link/LWG2905">2905</a></td><td>is_constructible_v<unique_ptr<P, D>, P, D const &> should be false when D is not copy constructible</td><td>Kona</td><td></td></tr> + <tr><td><a href="http://wg21.link/LWG2905">2905</a></td><td>is_constructible_v<unique_ptr<P, D>, P, D const &> should be false when D is not copy constructible</td><td>Kona</td><td>Complete</td></tr> <tr><td><a href="http://wg21.link/LWG2908">2908</a></td><td>The less-than operator for shared pointers could do more</td><td>Kona</td><td></td></tr> <tr><td><a href="http://wg21.link/LWG2911">2911</a></td><td>An is_aggregate type trait is needed</td><td>Kona</td><td>Complete</td></tr> <tr><td><a href="http://wg21.link/LWG2921">2921</a></td><td>packaged_task and type-erased allocators</td><td>Kona</td><td></td></tr> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits