This patch doesn't change very much, except for adding std::reinterpret_pointer_cast, but it makes it very easy to add array support to shared_ptr, as defined for the Library Fundamentals TS by https://wg21.link/n3920 and in the process of being added to C++17 by https://wg21.link/p0414r1
The main change is to consistently constrain all template constructors and assignment operators. In std::shared_ptr we just forward the checks to the std::__shared_ptr base class, so all the hard work is done there. The base uses traits that can easily be extended to handle array types without touching the uses of those traits (I have that patch ready). We also need to use shared_ptr<T>::element_type* in several places where we use T* today, because when T is an array type they are not the same thing. e.g. shared_ptr<int[]>::get() return int* not int[]*. In practical terms this changes very little, just makes some invalid code SFINAE-able instead of giving errors during instantiation, and gives a nicer static assertion message for invalid deleters. * include/backward/auto_ptr.h (__shared_ptr(auto_ptr&&)) (shared_ptr(auto_ptr&&)): Adjust template parameter lists. * include/bits/shared_ptr.h (__sp_compatible_with) (__sp_is_constructible): New helper traits for shared_ptr. (shared_ptr::_Convertible): Replace with _Constructible. (shared_ptr::_Constructible, shared_ptr::_Assignable): Forward checks to base class. (shared_ptr::shared_ptr, shared_ptr::operator=): Constrain template with _Constructible and _Assignable. (shared_ptr::shared_ptr(shared_ptr<_Tp1>, _Tp*)): Use element_type instead of _Tp. (operator<): Likewise. (operator>): Define in terms of operator<. (static_pointer_cast, const_pointer_cast, dynamic_pointer_cast): Use element_type instead of _Tp. (reinterpret_pointer_cast): Define for C++17. (weak_ptr::_Convertible): Replace with _Constructible. (weak_ptr::_Constructible, weak_ptr::_Assignable): Forward checks to base class. (weak_ptr::weak_ptr, weak_ptr::operator=): Constrain templates with _Constructible and _Assignable. * include/bits/shared_ptr_base.h (__shared_ptr::_Convertible): Replace with _Compatible. (__shared_ptr::_SafeConv): New constraint for incoming raw pointers. (__shared_ptr::_Compatible): New constraint for converting from other types of shared_ptr and weak_ptr. (__shared_ptr::_Assignable): Define in terms of _Compatible. (__shared_ptr::_UniqCompatible, __shared_ptr::_UniqAssignable): New constraints for converting from unique_ptr. (__shared_ptr::__shared_ptr, __shared_ptr::operator=): Constrain template with _SaveConf, _Compatible and _Assignable. Remove __glibcxx_function_requires concept checks. Add static assertion for deleter expression being well-formed. (__shared_ptr::__shared_ptr(__shared_ptr<_Tp1>, _Tp*)) (__shared_ptr::operator*, __shared_ptr::operator->) (__shared_ptr::get, __shared_ptr::_M_ptr): Use element_type instead of _Tp. (operator<): Likewise. (operator>): Define in terms of operator<. (static_pointer_cast, const_pointer_cast, dynamic_pointer_cast): Use element_type instead of _Tp. (reinterpret_pointer_cast): Define for C++17. (weak_ptr::_Convertible): Replace with _Compatible. (weak_ptr::_Compatible, weak_ptr::_Assignable): New constraints for conversions from other types of weak_ptr and shared_ptr. (__weak_ptr::__weak_ptr, __weak_ptr::operator=): Constrain templates with _Constructible and _Assignable. (__weak_ptr::_M_ptr): Use element_type instead of _Tp. * testsuite/20_util/shared_ptr/assign/auto_ptr_neg.cc: Adjust dg-error pattern. * testsuite/20_util/shared_ptr/cons/auto_ptr.cc: Test conversions. * testsuite/20_util/shared_ptr/cons/unique_ptr.cc: Likewise. * testsuite/20_util/shared_ptr/cons/void_neg.cc: Likewise. * testsuite/20_util/shared_ptr/casts/reinterpret.cc: New test. Tested powerpc64le-linux and x86_64-linux, and also tested with the libc++ and (parts of) the boost::shared_ptr tests. Committed to trunk.
commit 5e235c9782617f0b519f2273933ac257236c5e82 Author: Jonathan Wakely <jwak...@redhat.com> Date: Wed Oct 19 23:12:32 2016 +0100 Prepare shared_ptr for array support * include/backward/auto_ptr.h (__shared_ptr(auto_ptr&&)) (shared_ptr(auto_ptr&&)): Adjust template parameter lists. * include/bits/shared_ptr.h (__sp_compatible_with) (__sp_is_constructible): New helper traits for shared_ptr. (shared_ptr::_Convertible): Replace with _Constructible. (shared_ptr::_Constructible, shared_ptr::_Assignable): Forward checks to base class. (shared_ptr::shared_ptr, shared_ptr::operator=): Constrain template with _Constructible and _Assignable. (shared_ptr::shared_ptr(shared_ptr<_Tp1>, _Tp*)): Use element_type instead of _Tp. (operator<): Likewise. (operator>): Define in terms of operator<. (static_pointer_cast, const_pointer_cast, dynamic_pointer_cast): Use element_type instead of _Tp. (reinterpret_pointer_cast): Define for C++17. (weak_ptr::_Convertible): Replace with _Constructible. (weak_ptr::_Constructible, weak_ptr::_Assignable): Forward checks to base class. (weak_ptr::weak_ptr, weak_ptr::operator=): Constrain templates with _Constructible and _Assignable. * include/bits/shared_ptr_base.h (__shared_ptr::_Convertible): Replace with _Compatible. (__shared_ptr::_SafeConv): New constraint for incoming raw pointers. (__shared_ptr::_Compatible): New constraint for converting from other types of shared_ptr and weak_ptr. (__shared_ptr::_Assignable): Define in terms of _Compatible. (__shared_ptr::_UniqCompatible, __shared_ptr::_UniqAssignable): New constraints for converting from unique_ptr. (__shared_ptr::__shared_ptr, __shared_ptr::operator=): Constrain template with _SaveConf, _Compatible and _Assignable. Remove __glibcxx_function_requires concept checks. Add static assertion for deleter expression being well-formed. (__shared_ptr::__shared_ptr(__shared_ptr<_Tp1>, _Tp*)) (__shared_ptr::operator*, __shared_ptr::operator->) (__shared_ptr::get, __shared_ptr::_M_ptr): Use element_type instead of _Tp. (operator<): Likewise. (operator>): Define in terms of operator<. (static_pointer_cast, const_pointer_cast, dynamic_pointer_cast): Use element_type instead of _Tp. (reinterpret_pointer_cast): Define for C++17. (weak_ptr::_Convertible): Replace with _Compatible. (weak_ptr::_Compatible, weak_ptr::_Assignable): New constraints for conversions from other types of weak_ptr and shared_ptr. (__weak_ptr::__weak_ptr, __weak_ptr::operator=): Constrain templates with _Constructible and _Assignable. (__weak_ptr::_M_ptr): Use element_type instead of _Tp. * testsuite/20_util/shared_ptr/assign/auto_ptr_neg.cc: Adjust dg-error pattern. * testsuite/20_util/shared_ptr/cons/auto_ptr.cc: Test conversions. * testsuite/20_util/shared_ptr/cons/unique_ptr.cc: Likewise. * testsuite/20_util/shared_ptr/cons/void_neg.cc: Likewise. * testsuite/20_util/shared_ptr/casts/reinterpret.cc: New test. diff --git a/libstdc++-v3/include/backward/auto_ptr.h b/libstdc++-v3/include/backward/auto_ptr.h index 94911c8..855b6f9 100644 --- a/libstdc++-v3/include/backward/auto_ptr.h +++ b/libstdc++-v3/include/backward/auto_ptr.h @@ -302,7 +302,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { __r.release(); } template<typename _Tp, _Lock_policy _Lp> - template<typename _Tp1> + template<typename _Tp1, typename> inline __shared_ptr<_Tp, _Lp>::__shared_ptr(std::auto_ptr<_Tp1>&& __r) : _M_ptr(__r.get()), _M_refcount() @@ -315,7 +315,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _Tp> - template<typename _Tp1> + template<typename _Tp1, typename> inline shared_ptr<_Tp>::shared_ptr(std::auto_ptr<_Tp1>&& __r) : __shared_ptr<_Tp>(std::move(__r)) { } diff --git a/libstdc++-v3/include/bits/shared_ptr.h b/libstdc++-v3/include/bits/shared_ptr.h index 9b9261c..9f7a40c 100644 --- a/libstdc++-v3/include/bits/shared_ptr.h +++ b/libstdc++-v3/include/bits/shared_ptr.h @@ -92,16 +92,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp> class shared_ptr : public __shared_ptr<_Tp> { - template<typename _Ptr> - using _Convertible = typename - enable_if<is_convertible<_Ptr, _Tp*>::value>::type; + template<typename... _Args> + using _Constructible = typename enable_if< + is_constructible<__shared_ptr<_Tp>, _Args...>::value + >::type; - template<typename _Ptr> - using _Assignable = typename - enable_if<is_convertible<_Ptr, _Tp*>::value, shared_ptr&>::type; + template<typename _Arg> + using _Assignable = typename enable_if< + is_assignable<__shared_ptr<_Tp>&, _Arg>::value, shared_ptr& + >::type; public: + using element_type = typename __shared_ptr<_Tp>::element_type; + #if __cplusplus > 201402L # define __cpp_lib_shared_ptr_weak_type 201606 using weak_type = weak_ptr<_Tp>; @@ -110,8 +114,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @brief Construct an empty %shared_ptr. * @post use_count()==0 && get()==0 */ - constexpr shared_ptr() noexcept - : __shared_ptr<_Tp>() { } + constexpr shared_ptr() noexcept : __shared_ptr<_Tp>() { } shared_ptr(const shared_ptr&) noexcept = default; @@ -121,9 +124,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @post use_count() == 1 && get() == __p * @throw std::bad_alloc, in which case @c delete @a __p is called. */ - template<typename _Tp1> - explicit shared_ptr(_Tp1* __p) - : __shared_ptr<_Tp>(__p) { } + template<typename _Yp, typename = _Constructible<_Yp*>> + explicit + shared_ptr(_Yp* __p) : __shared_ptr<_Tp>(__p) { } /** * @brief Construct a %shared_ptr that owns the pointer @a __p @@ -138,8 +141,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * * __shared_ptr will release __p by calling __d(__p) */ - template<typename _Tp1, typename _Deleter> - shared_ptr(_Tp1* __p, _Deleter __d) + template<typename _Yp, typename _Deleter, + typename = _Constructible<_Yp*, _Deleter>> + shared_ptr(_Yp* __p, _Deleter __d) : __shared_ptr<_Tp>(__p, __d) { } /** @@ -174,8 +178,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * * __shared_ptr will release __p by calling __d(__p) */ - template<typename _Tp1, typename _Deleter, typename _Alloc> - shared_ptr(_Tp1* __p, _Deleter __d, _Alloc __a) + template<typename _Yp, typename _Deleter, typename _Alloc, + typename = _Constructible<_Yp*, _Deleter, _Alloc>> + shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a) : __shared_ptr<_Tp>(__p, __d, std::move(__a)) { } /** @@ -215,8 +220,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * assert(pii.use_count() == 2); * @endcode */ - template<typename _Tp1> - shared_ptr(const shared_ptr<_Tp1>& __r, _Tp* __p) noexcept + template<typename _Yp> + shared_ptr(const shared_ptr<_Yp>& __r, element_type* __p) noexcept : __shared_ptr<_Tp>(__r, __p) { } /** @@ -226,8 +231,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @param __r A %shared_ptr. * @post get() == __r.get() && use_count() == __r.use_count() */ - template<typename _Tp1, typename = _Convertible<_Tp1*>> - shared_ptr(const shared_ptr<_Tp1>& __r) noexcept + template<typename _Yp, + typename = _Constructible<const shared_ptr<_Yp>&>> + shared_ptr(const shared_ptr<_Yp>& __r) noexcept : __shared_ptr<_Tp>(__r) { } /** @@ -243,8 +249,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @param __r A %shared_ptr rvalue. * @post *this contains the old value of @a __r, @a __r is empty. */ - template<typename _Tp1, typename = _Convertible<_Tp1*>> - shared_ptr(shared_ptr<_Tp1>&& __r) noexcept + template<typename _Yp, typename = _Constructible<shared_ptr<_Yp>>> + shared_ptr(shared_ptr<_Yp>&& __r) noexcept : __shared_ptr<_Tp>(std::move(__r)) { } /** @@ -255,20 +261,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @throw bad_weak_ptr when __r.expired(), * in which case the constructor has no effect. */ - template<typename _Tp1> - explicit shared_ptr(const weak_ptr<_Tp1>& __r) + template<typename _Yp, typename = _Constructible<const weak_ptr<_Yp>&>> + explicit shared_ptr(const weak_ptr<_Yp>& __r) : __shared_ptr<_Tp>(__r) { } #if _GLIBCXX_USE_DEPRECATED - template<typename _Tp1> - shared_ptr(std::auto_ptr<_Tp1>&& __r); + template<typename _Yp, typename = _Constructible<auto_ptr<_Yp>>> + shared_ptr(auto_ptr<_Yp>&& __r); #endif // _GLIBCXX_RESOLVE_LIB_DEFECTS // 2399. shared_ptr's constructor from unique_ptr should be constrained - template<typename _Tp1, typename _Del, typename - = _Convertible<typename unique_ptr<_Tp1, _Del>::pointer>> - shared_ptr(std::unique_ptr<_Tp1, _Del>&& __r) + template<typename _Yp, typename _Del, + typename = _Constructible<unique_ptr<_Yp, _Del>>> + shared_ptr(unique_ptr<_Yp, _Del>&& __r) : __shared_ptr<_Tp>(std::move(__r)) { } /** @@ -279,18 +285,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION shared_ptr& operator=(const shared_ptr&) noexcept = default; - template<typename _Tp1> - _Assignable<_Tp1*> - operator=(const shared_ptr<_Tp1>& __r) noexcept + template<typename _Yp> + _Assignable<const shared_ptr<_Yp>&> + operator=(const shared_ptr<_Yp>& __r) noexcept { this->__shared_ptr<_Tp>::operator=(__r); return *this; } #if _GLIBCXX_USE_DEPRECATED - template<typename _Tp1> - shared_ptr& - operator=(std::auto_ptr<_Tp1>&& __r) + template<typename _Yp> + _Assignable<auto_ptr<_Yp>> + operator=(auto_ptr<_Yp>&& __r) { this->__shared_ptr<_Tp>::operator=(std::move(__r)); return *this; @@ -304,17 +310,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } - template<class _Tp1> - _Assignable<_Tp1*> - operator=(shared_ptr<_Tp1>&& __r) noexcept + template<class _Yp> + _Assignable<shared_ptr<_Yp>> + operator=(shared_ptr<_Yp>&& __r) noexcept { this->__shared_ptr<_Tp>::operator=(std::move(__r)); return *this; } - template<typename _Tp1, typename _Del> - _Assignable<typename unique_ptr<_Tp1, _Del>::pointer> - operator=(std::unique_ptr<_Tp1, _Del>&& __r) + template<typename _Yp, typename _Del> + _Assignable<unique_ptr<_Yp, _Del>> + operator=(unique_ptr<_Yp, _Del>&& __r) { this->__shared_ptr<_Tp>::operator=(std::move(__r)); return *this; @@ -328,8 +334,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : __shared_ptr<_Tp>(__tag, __a, std::forward<_Args>(__args)...) { } - template<typename _Tp1, typename _Alloc, typename... _Args> - friend shared_ptr<_Tp1> + template<typename _Yp, typename _Alloc, typename... _Args> + friend shared_ptr<_Yp> allocate_shared(const _Alloc& __a, _Args&&... __args); // This constructor is non-standard, it is used by weak_ptr::lock(). @@ -340,10 +346,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; // 20.7.2.2.7 shared_ptr comparisons - template<typename _Tp1, typename _Tp2> + template<typename _Tp, typename _Up> inline bool - operator==(const shared_ptr<_Tp1>& __a, - const shared_ptr<_Tp2>& __b) noexcept + operator==(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept { return __a.get() == __b.get(); } template<typename _Tp> @@ -356,10 +361,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator==(nullptr_t, const shared_ptr<_Tp>& __a) noexcept { return !__a; } - template<typename _Tp1, typename _Tp2> + template<typename _Tp, typename _Up> inline bool - operator!=(const shared_ptr<_Tp1>& __a, - const shared_ptr<_Tp2>& __b) noexcept + operator!=(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept { return __a.get() != __b.get(); } template<typename _Tp> @@ -372,29 +376,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator!=(nullptr_t, const shared_ptr<_Tp>& __a) noexcept { return (bool)__a; } - template<typename _Tp1, typename _Tp2> + template<typename _Tp, typename _Up> inline bool - operator<(const shared_ptr<_Tp1>& __a, - const shared_ptr<_Tp2>& __b) noexcept + operator<(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept { - typedef typename std::common_type<_Tp1*, _Tp2*>::type _CT; - return std::less<_CT>()(__a.get(), __b.get()); + using _Tp_elt = typename shared_ptr<_Tp>::element_type; + using _Up_elt = typename shared_ptr<_Up>::element_type; + using _Vp = typename common_type<_Tp_elt*, _Up_elt*>::type; + return less<_Vp>()(__a.get(), __b.get()); } template<typename _Tp> inline bool operator<(const shared_ptr<_Tp>& __a, nullptr_t) noexcept - { return std::less<_Tp*>()(__a.get(), nullptr); } + { + using _Tp_elt = typename shared_ptr<_Tp>::element_type; + return less<_Tp_elt*>()(__a.get(), nullptr); + } template<typename _Tp> inline bool operator<(nullptr_t, const shared_ptr<_Tp>& __a) noexcept - { return std::less<_Tp*>()(nullptr, __a.get()); } + { + using _Tp_elt = typename shared_ptr<_Tp>::element_type; + return less<_Tp_elt*>()(nullptr, __a.get()); + } - template<typename _Tp1, typename _Tp2> + template<typename _Tp, typename _Up> inline bool - operator<=(const shared_ptr<_Tp1>& __a, - const shared_ptr<_Tp2>& __b) noexcept + operator<=(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept { return !(__b < __a); } template<typename _Tp> @@ -407,26 +417,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator<=(nullptr_t, const shared_ptr<_Tp>& __a) noexcept { return !(__a < nullptr); } - template<typename _Tp1, typename _Tp2> + template<typename _Tp, typename _Up> inline bool - operator>(const shared_ptr<_Tp1>& __a, - const shared_ptr<_Tp2>& __b) noexcept + operator>(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept { return (__b < __a); } template<typename _Tp> inline bool operator>(const shared_ptr<_Tp>& __a, nullptr_t) noexcept - { return std::less<_Tp*>()(nullptr, __a.get()); } + { return nullptr < __a; } template<typename _Tp> inline bool operator>(nullptr_t, const shared_ptr<_Tp>& __a) noexcept - { return std::less<_Tp*>()(__a.get(), nullptr); } + { return __a < nullptr; } - template<typename _Tp1, typename _Tp2> + template<typename _Tp, typename _Up> inline bool - operator>=(const shared_ptr<_Tp1>& __a, - const shared_ptr<_Tp2>& __b) noexcept + operator>=(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept { return !(__a < __b); } template<typename _Tp> @@ -450,25 +458,41 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { __a.swap(__b); } // 20.7.2.2.9 shared_ptr casts. - template<typename _Tp, typename _Tp1> + template<typename _Tp, typename _Up> inline shared_ptr<_Tp> - static_pointer_cast(const shared_ptr<_Tp1>& __r) noexcept - { return shared_ptr<_Tp>(__r, static_cast<_Tp*>(__r.get())); } - - template<typename _Tp, typename _Tp1> - inline shared_ptr<_Tp> - const_pointer_cast(const shared_ptr<_Tp1>& __r) noexcept - { return shared_ptr<_Tp>(__r, const_cast<_Tp*>(__r.get())); } - - template<typename _Tp, typename _Tp1> - inline shared_ptr<_Tp> - dynamic_pointer_cast(const shared_ptr<_Tp1>& __r) noexcept + static_pointer_cast(const shared_ptr<_Up>& __r) noexcept { - if (_Tp* __p = dynamic_cast<_Tp*>(__r.get())) - return shared_ptr<_Tp>(__r, __p); - return shared_ptr<_Tp>(); + using _Sp = shared_ptr<_Tp>; + return _Sp(__r, static_cast<typename _Sp::element_type*>(__r.get())); } + template<typename _Tp, typename _Up> + inline shared_ptr<_Tp> + const_pointer_cast(const shared_ptr<_Up>& __r) noexcept + { + using _Sp = shared_ptr<_Tp>; + return _Sp(__r, const_cast<typename _Sp::element_type*>(__r.get())); + } + + template<typename _Tp, typename _Up> + inline shared_ptr<_Tp> + dynamic_pointer_cast(const shared_ptr<_Up>& __r) noexcept + { + using _Sp = shared_ptr<_Tp>; + if (auto* __p = dynamic_cast<typename _Sp::element_type*>(__r.get())) + return _Sp(__r, __p); + return _Sp(); + } + +#if __cplusplus > 201402L + template<typename _Tp, typename _Up> + inline shared_ptr<_Tp> + reinterpret_pointer_cast(const shared_ptr<_Up>& __r) noexcept + { + using _Sp = shared_ptr<_Tp>; + return _Sp(__r, reinterpret_cast<typename _Sp::element_type*>(__r.get())); + } +#endif /** * @brief A smart pointer with weak semantics. @@ -478,43 +502,50 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp> class weak_ptr : public __weak_ptr<_Tp> { - template<typename _Ptr> - using _Convertible - = typename enable_if<is_convertible<_Ptr, _Tp*>::value>::type; + template<typename _Arg> + using _Constructible = typename enable_if< + is_constructible<__weak_ptr<_Tp>, _Arg>::value + >::type; + + template<typename _Arg> + using _Assignable = typename enable_if< + is_assignable<__weak_ptr<_Tp>&, _Arg>::value, weak_ptr& + >::type; public: constexpr weak_ptr() noexcept = default; - template<typename _Tp1, typename = _Convertible<_Tp1*>> - weak_ptr(const shared_ptr<_Tp1>& __r) noexcept + template<typename _Yp, + typename = _Constructible<const shared_ptr<_Yp>&>> + weak_ptr(const shared_ptr<_Yp>& __r) noexcept : __weak_ptr<_Tp>(__r) { } weak_ptr(const weak_ptr&) noexcept = default; - template<typename _Tp1, typename = _Convertible<_Tp1*>> - weak_ptr(const weak_ptr<_Tp1>& __r) noexcept + template<typename _Yp, typename = _Constructible<const weak_ptr<_Yp>&>> + weak_ptr(const weak_ptr<_Yp>& __r) noexcept : __weak_ptr<_Tp>(__r) { } weak_ptr(weak_ptr&&) noexcept = default; - template<typename _Tp1, typename = _Convertible<_Tp1*>> - weak_ptr(weak_ptr<_Tp1>&& __r) noexcept + template<typename _Yp, typename = _Constructible<weak_ptr<_Yp>>> + weak_ptr(weak_ptr<_Yp>&& __r) noexcept : __weak_ptr<_Tp>(std::move(__r)) { } weak_ptr& operator=(const weak_ptr& __r) noexcept = default; - template<typename _Tp1> - weak_ptr& - operator=(const weak_ptr<_Tp1>& __r) noexcept + template<typename _Yp> + _Assignable<const weak_ptr<_Yp>&> + operator=(const weak_ptr<_Yp>& __r) noexcept { this->__weak_ptr<_Tp>::operator=(__r); return *this; } - template<typename _Tp1> - weak_ptr& - operator=(const shared_ptr<_Tp1>& __r) noexcept + template<typename _Yp> + _Assignable<const shared_ptr<_Yp>&> + operator=(const shared_ptr<_Yp>& __r) noexcept { this->__weak_ptr<_Tp>::operator=(__r); return *this; @@ -523,9 +554,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION weak_ptr& operator=(weak_ptr&& __r) noexcept = default; - template<typename _Tp1> - weak_ptr& - operator=(weak_ptr<_Tp1>&& __r) noexcept + template<typename _Yp> + _Assignable<weak_ptr<_Yp>> + operator=(weak_ptr<_Yp>&& __r) noexcept { this->__weak_ptr<_Tp>::operator=(std::move(__r)); return *this; diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h index c0686ad..c74c92a 100644 --- a/libstdc++-v3/include/bits/shared_ptr_base.h +++ b/libstdc++-v3/include/bits/shared_ptr_base.h @@ -847,19 +847,55 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_pi = nullptr; } + // Helper traits for shared_ptr + + template<typename _Yp_ptr, typename _Tp_ptr> + struct __sp_compatible_with + : false_type + { }; + + template<typename _Yp, typename _Tp> + struct __sp_compatible_with<_Yp*, _Tp*> + : is_convertible<_Yp*, _Tp*>::type + { }; + template<typename _Tp, _Lock_policy _Lp> class __shared_ptr { - template<typename _Ptr> - using _Convertible - = typename enable_if<is_convertible<_Ptr, _Tp*>::value>::type; + public: + using element_type = _Tp; - template<typename _Ptr> - using _Assignable = typename - enable_if<is_convertible<_Ptr, _Tp*>::value, __shared_ptr&>::type; + private: + // Trait to check if shared_ptr<T> can be constructed from Y*. + template<typename _Tp1, typename _Yp> + using __sp_is_constructible = is_convertible<_Yp*, _Tp1*>; + + // Constraint for taking ownership of a pointer of type _Yp*: + template<typename _Yp> + using _SafeConv + = typename enable_if<__sp_is_constructible<_Tp, _Yp>::value>::type; + + // Constraint for construction from shared_ptr and weak_ptr: + template<typename _Yp, typename _Res = void> + using _Compatible = typename + enable_if<__sp_compatible_with<_Yp*, _Tp*>::value, _Res>::type; + + // Constraint for assignment from shared_ptr and weak_ptr: + template<typename _Yp> + using _Assignable = _Compatible<_Yp, __shared_ptr&>; + + // Constraint for construction from unique_ptr: + template<typename _Yp, typename _Del, typename _Res = void, + typename _Ptr = typename unique_ptr<_Yp, _Del>::pointer> + using _UniqCompatible = typename enable_if< + is_convertible<_Ptr, element_type*>::value + , _Res>::type; + + // Constraint for assignment from unique_ptr: + template<typename _Yp, typename _Del> + using _UniqAssignable = _UniqCompatible<_Yp, _Del, __shared_ptr&>; public: - typedef _Tp element_type; #if __cplusplus > 201402L using weak_type = __weak_ptr<_Tp, _Lp>; @@ -869,31 +905,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : _M_ptr(0), _M_refcount() { } - template<typename _Tp1> - explicit __shared_ptr(_Tp1* __p) - : _M_ptr(__p), _M_refcount(__p) + template<typename _Yp, typename = _SafeConv<_Yp>> + explicit + __shared_ptr(_Yp* __p) + : _M_ptr(__p), _M_refcount(__p) { - __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>) - static_assert( !is_void<_Tp1>::value, "incomplete type" ); - static_assert( sizeof(_Tp1) > 0, "incomplete type" ); + static_assert( !is_void<_Yp>::value, "incomplete type" ); + static_assert( sizeof(_Yp) > 0, "incomplete type" ); _M_enable_shared_from_this_with(__p); } - template<typename _Tp1, typename _Deleter> - __shared_ptr(_Tp1* __p, _Deleter __d) + template<typename _Yp, typename _Deleter, typename = _SafeConv<_Yp>> + __shared_ptr(_Yp* __p, _Deleter __d) : _M_ptr(__p), _M_refcount(__p, __d) { - __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>) - // TODO requires _Deleter CopyConstructible and __d(__p) well-formed + static_assert(__is_callable<_Deleter(_Yp*)>::value, + "deleter expression d(p) is well-formed"); _M_enable_shared_from_this_with(__p); } - template<typename _Tp1, typename _Deleter, typename _Alloc> - __shared_ptr(_Tp1* __p, _Deleter __d, _Alloc __a) + template<typename _Yp, typename _Deleter, typename _Alloc, + typename = _SafeConv<_Yp>> + __shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a) : _M_ptr(__p), _M_refcount(__p, __d, std::move(__a)) { - __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>) - // TODO requires _Deleter CopyConstructible and __d(__p) well-formed + static_assert(__is_callable<_Deleter(_Yp*)>::value, + "deleter expression d(p) is well-formed"); _M_enable_shared_from_this_with(__p); } @@ -907,8 +944,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : _M_ptr(0), _M_refcount(__p, __d, std::move(__a)) { } - template<typename _Tp1> - __shared_ptr(const __shared_ptr<_Tp1, _Lp>& __r, _Tp* __p) noexcept + template<typename _Yp> + __shared_ptr(const __shared_ptr<_Yp, _Lp>& __r, + element_type* __p) noexcept : _M_ptr(__p), _M_refcount(__r._M_refcount) // never throws { } @@ -916,8 +954,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __shared_ptr& operator=(const __shared_ptr&) noexcept = default; ~__shared_ptr() = default; - template<typename _Tp1, typename = _Convertible<_Tp1*>> - __shared_ptr(const __shared_ptr<_Tp1, _Lp>& __r) noexcept + template<typename _Yp, typename = _Compatible<_Yp>> + __shared_ptr(const __shared_ptr<_Yp, _Lp>& __r) noexcept : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) { } @@ -928,32 +966,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __r._M_ptr = 0; } - template<typename _Tp1, typename = _Convertible<_Tp1*>> - __shared_ptr(__shared_ptr<_Tp1, _Lp>&& __r) noexcept + template<typename _Yp, typename = _Compatible<_Yp>> + __shared_ptr(__shared_ptr<_Yp, _Lp>&& __r) noexcept : _M_ptr(__r._M_ptr), _M_refcount() { _M_refcount._M_swap(__r._M_refcount); __r._M_ptr = 0; } - template<typename _Tp1> - explicit __shared_ptr(const __weak_ptr<_Tp1, _Lp>& __r) + template<typename _Yp, typename = _Compatible<_Yp>> + explicit __shared_ptr(const __weak_ptr<_Yp, _Lp>& __r) : _M_refcount(__r._M_refcount) // may throw { - __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>) - // It is now safe to copy __r._M_ptr, as // _M_refcount(__r._M_refcount) did not throw. _M_ptr = __r._M_ptr; } // If an exception is thrown this constructor has no effect. - template<typename _Tp1, typename _Del, typename - = _Convertible<typename unique_ptr<_Tp1, _Del>::pointer>> - __shared_ptr(std::unique_ptr<_Tp1, _Del>&& __r) + template<typename _Yp, typename _Del, + typename = _UniqCompatible<_Yp, _Del>> + __shared_ptr(unique_ptr<_Yp, _Del>&& __r) : _M_ptr(__r.get()), _M_refcount() { - __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>) auto __raw = _S_raw_ptr(__r.get()); _M_refcount = __shared_count<_Lp>(std::move(__r)); _M_enable_shared_from_this_with(__raw); @@ -961,15 +996,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if _GLIBCXX_USE_DEPRECATED // Postcondition: use_count() == 1 and __r.get() == 0 - template<typename _Tp1> - __shared_ptr(std::auto_ptr<_Tp1>&& __r); + template<typename _Yp, typename = _Compatible<_Yp>> + __shared_ptr(auto_ptr<_Yp>&& __r); #endif constexpr __shared_ptr(nullptr_t) noexcept : __shared_ptr() { } - template<typename _Tp1> - _Assignable<_Tp1*> - operator=(const __shared_ptr<_Tp1, _Lp>& __r) noexcept + template<typename _Yp> + _Assignable<_Yp> + operator=(const __shared_ptr<_Yp, _Lp>& __r) noexcept { _M_ptr = __r._M_ptr; _M_refcount = __r._M_refcount; // __shared_count::op= doesn't throw @@ -977,9 +1012,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #if _GLIBCXX_USE_DEPRECATED - template<typename _Tp1> - __shared_ptr& - operator=(std::auto_ptr<_Tp1>&& __r) + template<typename _Yp> + _Assignable<_Yp> + operator=(auto_ptr<_Yp>&& __r) { __shared_ptr(std::move(__r)).swap(*this); return *this; @@ -993,17 +1028,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } - template<class _Tp1> - _Assignable<_Tp1*> - operator=(__shared_ptr<_Tp1, _Lp>&& __r) noexcept + template<class _Yp> + _Assignable<_Yp> + operator=(__shared_ptr<_Yp, _Lp>&& __r) noexcept { __shared_ptr(std::move(__r)).swap(*this); return *this; } - template<typename _Tp1, typename _Del> - _Assignable<typename unique_ptr<_Tp1, _Del>::pointer> - operator=(std::unique_ptr<_Tp1, _Del>&& __r) + template<typename _Yp, typename _Del> + _UniqAssignable<_Yp, _Del> + operator=(unique_ptr<_Yp, _Del>&& __r) { __shared_ptr(std::move(__r)).swap(*this); return *this; @@ -1013,41 +1048,41 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION reset() noexcept { __shared_ptr().swap(*this); } - template<typename _Tp1> - _Convertible<_Tp1*> - reset(_Tp1* __p) // _Tp1 must be complete. + template<typename _Yp> + _SafeConv<_Yp> + reset(_Yp* __p) // _Yp must be complete. { // Catch self-reset errors. __glibcxx_assert(__p == 0 || __p != _M_ptr); __shared_ptr(__p).swap(*this); } - template<typename _Tp1, typename _Deleter> - _Convertible<_Tp1*> - reset(_Tp1* __p, _Deleter __d) + template<typename _Yp, typename _Deleter> + _SafeConv<_Yp> + reset(_Yp* __p, _Deleter __d) { __shared_ptr(__p, __d).swap(*this); } - template<typename _Tp1, typename _Deleter, typename _Alloc> - _Convertible<_Tp1*> - reset(_Tp1* __p, _Deleter __d, _Alloc __a) + template<typename _Yp, typename _Deleter, typename _Alloc> + _SafeConv<_Yp> + reset(_Yp* __p, _Deleter __d, _Alloc __a) { __shared_ptr(__p, __d, std::move(__a)).swap(*this); } // Allow class instantiation when _Tp is [cv-qual] void. - typename std::add_lvalue_reference<_Tp>::type + typename std::add_lvalue_reference<element_type>::type operator*() const noexcept { __glibcxx_assert(_M_ptr != 0); return *_M_ptr; } - _Tp* + element_type* operator->() const noexcept { _GLIBCXX_DEBUG_PEDASSERT(_M_ptr != 0); return _M_ptr; } - _Tp* + element_type* get() const noexcept { return _M_ptr; } @@ -1192,7 +1227,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Del, typename _Tp1, _Lock_policy _Lp1> friend _Del* get_deleter(const __shared_ptr<_Tp1, _Lp1>&) noexcept; - _Tp* _M_ptr; // Contained pointer. + element_type* _M_ptr; // Contained pointer. __shared_count<_Lp> _M_refcount; // Reference counter. }; @@ -1230,24 +1265,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator!=(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept { return (bool)__a; } - template<typename _Tp1, typename _Tp2, _Lock_policy _Lp> + template<typename _Tp, typename _Up, _Lock_policy _Lp> inline bool - operator<(const __shared_ptr<_Tp1, _Lp>& __a, - const __shared_ptr<_Tp2, _Lp>& __b) noexcept + operator<(const __shared_ptr<_Tp, _Lp>& __a, + const __shared_ptr<_Up, _Lp>& __b) noexcept { - typedef typename std::common_type<_Tp1*, _Tp2*>::type _CT; - return std::less<_CT>()(__a.get(), __b.get()); + using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type; + using _Up_elt = typename __shared_ptr<_Up, _Lp>::element_type; + using _Vp = typename common_type<_Tp_elt*, _Up_elt*>::type; + return less<_Vp>()(__a.get(), __b.get()); } template<typename _Tp, _Lock_policy _Lp> inline bool operator<(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept - { return std::less<_Tp*>()(__a.get(), nullptr); } + { + using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type; + return less<_Tp_elt*>()(__a.get(), nullptr); + } template<typename _Tp, _Lock_policy _Lp> inline bool operator<(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept - { return std::less<_Tp*>()(nullptr, __a.get()); } + { + using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type; + return less<_Tp_elt*>()(nullptr, __a.get()); + } template<typename _Tp1, typename _Tp2, _Lock_policy _Lp> inline bool @@ -1274,12 +1317,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, _Lock_policy _Lp> inline bool operator>(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept - { return std::less<_Tp*>()(nullptr, __a.get()); } + { return nullptr < __a; } template<typename _Tp, _Lock_policy _Lp> inline bool operator>(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept - { return std::less<_Tp*>()(__a.get(), nullptr); } + { return __a < nullptr; } template<typename _Tp1, typename _Tp2, _Lock_policy _Lp> inline bool @@ -1329,7 +1372,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, typename _Tp1, _Lock_policy _Lp> inline __shared_ptr<_Tp, _Lp> static_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept - { return __shared_ptr<_Tp, _Lp>(__r, static_cast<_Tp*>(__r.get())); } + { + using _Sp = __shared_ptr<_Tp, _Lp>; + return _Sp(__r, static_cast<typename _Sp::element_type*>(__r.get())); + } // The seemingly equivalent code: // shared_ptr<_Tp, _Lp>(const_cast<_Tp*>(__r.get())) @@ -1339,7 +1385,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, typename _Tp1, _Lock_policy _Lp> inline __shared_ptr<_Tp, _Lp> const_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept - { return __shared_ptr<_Tp, _Lp>(__r, const_cast<_Tp*>(__r.get())); } + { + using _Sp = __shared_ptr<_Tp, _Lp>; + return _Sp(__r, const_cast<typename _Sp::element_type*>(__r.get())); + } // The seemingly equivalent code: // shared_ptr<_Tp, _Lp>(dynamic_cast<_Tp*>(__r.get())) @@ -1350,21 +1399,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline __shared_ptr<_Tp, _Lp> dynamic_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept { - if (_Tp* __p = dynamic_cast<_Tp*>(__r.get())) - return __shared_ptr<_Tp, _Lp>(__r, __p); - return __shared_ptr<_Tp, _Lp>(); + using _Sp = __shared_ptr<_Tp, _Lp>; + if (auto* __p = dynamic_cast<typename _Sp::element_type*>(__r.get())) + return _Sp(__r, __p); + return _Sp(); } +#if __cplusplus > 201402L + template<typename _Tp, typename _Tp1, _Lock_policy _Lp> + inline __shared_ptr<_Tp, _Lp> + reinterpret_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept + { + using _Sp = __shared_ptr<_Tp, _Lp>; + return _Sp(__r, reinterpret_cast<typename _Sp::element_type*>(__r.get())); + } +#endif template<typename _Tp, _Lock_policy _Lp> class __weak_ptr { - template<typename _Ptr> - using _Convertible - = typename enable_if<is_convertible<_Ptr, _Tp*>::value>::type; + template<typename _Yp, typename _Res = void> + using _Compatible = typename + enable_if<__sp_compatible_with<_Yp*, _Tp*>::value, _Res>::type; + + // Constraint for assignment from shared_ptr and weak_ptr: + template<typename _Yp> + using _Assignable = _Compatible<_Yp, __weak_ptr&>; public: - typedef _Tp element_type; + using element_type = _Tp; constexpr __weak_ptr() noexcept : _M_ptr(nullptr), _M_refcount() @@ -1388,13 +1451,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // // It is not possible to avoid spurious access violations since // in multithreaded programs __r._M_ptr may be invalidated at any point. - template<typename _Tp1, typename = _Convertible<_Tp1*>> - __weak_ptr(const __weak_ptr<_Tp1, _Lp>& __r) noexcept + template<typename _Yp, typename = _Compatible<_Yp>> + __weak_ptr(const __weak_ptr<_Yp, _Lp>& __r) noexcept : _M_refcount(__r._M_refcount) { _M_ptr = __r.lock().get(); } - template<typename _Tp1, typename = _Convertible<_Tp1*>> - __weak_ptr(const __shared_ptr<_Tp1, _Lp>& __r) noexcept + template<typename _Yp, typename = _Compatible<_Yp>> + __weak_ptr(const __shared_ptr<_Yp, _Lp>& __r) noexcept : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) { } @@ -1402,26 +1465,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : _M_ptr(__r._M_ptr), _M_refcount(std::move(__r._M_refcount)) { __r._M_ptr = nullptr; } - template<typename _Tp1, typename = _Convertible<_Tp1*>> - __weak_ptr(__weak_ptr<_Tp1, _Lp>&& __r) noexcept + template<typename _Yp, typename = _Compatible<_Yp>> + __weak_ptr(__weak_ptr<_Yp, _Lp>&& __r) noexcept : _M_ptr(__r.lock().get()), _M_refcount(std::move(__r._M_refcount)) { __r._M_ptr = nullptr; } __weak_ptr& operator=(const __weak_ptr& __r) noexcept = default; - template<typename _Tp1> - __weak_ptr& - operator=(const __weak_ptr<_Tp1, _Lp>& __r) noexcept + template<typename _Yp> + _Assignable<_Yp> + operator=(const __weak_ptr<_Yp, _Lp>& __r) noexcept { _M_ptr = __r.lock().get(); _M_refcount = __r._M_refcount; return *this; } - template<typename _Tp1> - __weak_ptr& - operator=(const __shared_ptr<_Tp1, _Lp>& __r) noexcept + template<typename _Yp> + _Assignable<_Yp> + operator=(const __shared_ptr<_Yp, _Lp>& __r) noexcept { _M_ptr = __r._M_ptr; _M_refcount = __r._M_refcount; @@ -1437,9 +1500,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } - template<typename _Tp1> - __weak_ptr& - operator=(__weak_ptr<_Tp1, _Lp>&& __r) noexcept + template<typename _Yp> + _Assignable<_Yp> + operator=(__weak_ptr<_Yp, _Lp>&& __r) noexcept { _M_ptr = __r.lock().get(); _M_refcount = std::move(__r._M_refcount); @@ -1497,7 +1560,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION friend class __enable_shared_from_this<_Tp, _Lp>; friend class enable_shared_from_this<_Tp>; - _Tp* _M_ptr; // Contained pointer. + element_type* _M_ptr; // Contained pointer. __weak_count<_Lp> _M_refcount; // Reference counter. }; diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/assign/auto_ptr_neg.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/assign/auto_ptr_neg.cc index 56d818e..0558cf4 100644 --- a/libstdc++-v3/testsuite/20_util/shared_ptr/assign/auto_ptr_neg.cc +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/assign/auto_ptr_neg.cc @@ -34,7 +34,7 @@ test01() { std::shared_ptr<A> a; std::auto_ptr<B> b; - a = std::move(b); // { dg-error "here" } + a = std::move(b); // { dg-error "no match" } return 0; } diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/casts/reinterpret.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/casts/reinterpret.cc new file mode 100644 index 0000000..e519f0e --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/casts/reinterpret.cc @@ -0,0 +1,42 @@ +// { dg-options "-std=gnu++17" } +// { dg-do compile { target c++1z } } + +// Copyright (C) 2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// 20.11.2.2.9 shared_ptr casts [util.smartptr.shared.cast] + +#include <memory> +#include <testsuite_tr1.h> + +struct MyP { virtual ~MyP() { }; }; +struct MyDP : MyP { }; + +int main() +{ + using __gnu_test::check_ret_type; + using std::shared_ptr; + using std::reinterpret_pointer_cast; + + shared_ptr<double> spd; + shared_ptr<const int> spci; + shared_ptr<MyP> spa; + + check_ret_type<shared_ptr<void> >(reinterpret_pointer_cast<void>(spd)); + check_ret_type<shared_ptr<const short> >(reinterpret_pointer_cast<const short>(spci)); + check_ret_type<shared_ptr<MyDP> >(reinterpret_pointer_cast<MyDP>(spa)); +} diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/auto_ptr.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/auto_ptr.cc index 7a99490..52481c1 100644 --- a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/auto_ptr.cc +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/auto_ptr.cc @@ -25,10 +25,28 @@ struct A { }; +int destroyed = 0; +struct B : A { ~B() { ++destroyed; } }; + // 20.6.6.2.1 shared_ptr constructors [util.smartptr.shared.const] // Construction from auto_ptr -int + +template<typename From, typename To> +constexpr bool constructible() +{ + using namespace std; + return is_constructible<shared_ptr<To>, auto_ptr<From>>::value + && is_constructible<shared_ptr<const To>, auto_ptr<From>>::value + && is_constructible<shared_ptr<const To>, auto_ptr<const From>>::value; +} + +static_assert( constructible< A, A >(), "A -> A compatible" ); +static_assert( constructible< B, A >(), "B -> A compatible" ); +static_assert( constructible< int, int >(), "int -> int compatible" ); +static_assert( !constructible< int, long >(), "int -> long not compatible" ); + +void test01() { std::auto_ptr<A> a(new A); @@ -36,13 +54,24 @@ test01() VERIFY( a.get() == 0 ); VERIFY( a2.get() != 0 ); VERIFY( a2.use_count() == 1 ); +} - return 0; +void +test02() +{ + std::auto_ptr<B> b(new B); + std::shared_ptr<A> a(std::move(b)); + VERIFY( b.get() == 0 ); + VERIFY( a.get() != 0 ); + VERIFY( a.use_count() == 1 ); + a.reset(); + VERIFY( destroyed == 1 ); } int main() { test01(); + test02(); return 0; } diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/unique_ptr.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/unique_ptr.cc index 18e6616..52bbd3b 100644 --- a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/unique_ptr.cc +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/unique_ptr.cc @@ -24,10 +24,28 @@ struct A { }; +int destroyed = 0; +struct B : A { ~B() { ++destroyed; } }; + // 20.7.2.2.1 shared_ptr constructors [util.smartptr.shared.const] // Construction from unique_ptr -int + +template<typename From, typename To> +constexpr bool constructible() +{ + using namespace std; + return is_constructible<shared_ptr<To>, unique_ptr<From>>::value + && is_constructible<shared_ptr<const To>, unique_ptr<From>>::value + && is_constructible<shared_ptr<const To>, unique_ptr<const From>>::value; +} + +static_assert( constructible< A, A >(), "A -> A compatible" ); +static_assert( constructible< B, A >(), "B -> A compatible" ); +static_assert( constructible< int, int >(), "int -> int compatible" ); +static_assert( !constructible< int, long >(), "int -> long not compatible" ); + +void test01() { std::unique_ptr<A> up(new A); @@ -35,13 +53,24 @@ test01() VERIFY( up.get() == 0 ); VERIFY( sp.get() != 0 ); VERIFY( sp.use_count() == 1 ); +} - return 0; +void +test02() +{ + std::unique_ptr<B> b(new B); + std::shared_ptr<A> a(std::move(b)); + VERIFY( b.get() == 0 ); + VERIFY( a.get() != 0 ); + VERIFY( a.use_count() == 1 ); + a.reset(); + VERIFY( destroyed == 1 ); } int main() { test01(); + test02(); return 0; } diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/void_neg.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/void_neg.cc index 0cadf25..ba28644 100644 --- a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/void_neg.cc +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/void_neg.cc @@ -26,3 +26,7 @@ void test01() std::shared_ptr<void> p((void*)nullptr); // { dg-error "here" } // { dg-error "incomplete" "" { target *-*-* } 0 } } + +using std::shared_ptr; +using std::is_constructible; +static_assert(!is_constructible<shared_ptr<void>, const void*>::value, "");