diff options
author | pateldeev <pateldeev@nevada.unr.edu> | 2023-07-18 17:48:53 +0200 |
---|---|---|
committer | Mark de Wever <koraq@xs4all.nl> | 2023-07-18 20:04:21 +0200 |
commit | 347f45ed2b6d951a19fdef99c468f4f8f7f0b979 (patch) | |
tree | de231ac6e5a2c867f889ac5c40bbc2e08cde3051 /libcxx | |
parent | ef70fe4d264d20abdd8476605650479a96a62071 (diff) | |
download | llvm-347f45ed2b6d951a19fdef99c468f4f8f7f0b979.zip llvm-347f45ed2b6d951a19fdef99c468f4f8f7f0b979.tar.gz llvm-347f45ed2b6d951a19fdef99c468f4f8f7f0b979.tar.bz2 |
[libc++][LWG 2996] Implement c++20 shared_ptr rvalue overloads.
Implement c++20 `shared_ptr` rvalue overloads for aliasing constructor and pointer casts. See https://cplusplus.github.io/LWG/issue2996
Commit from
"patedeev" <dkp10000@gmail.com>
Reviewed By: philnik, #libc, ldionne, pateldeev
Differential Revision: https://reviews.llvm.org/D135548
Diffstat (limited to 'libcxx')
7 files changed, 123 insertions, 14 deletions
diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv index 9bdeeb0..16161c3 100644 --- a/libcxx/docs/Status/Cxx20Issues.csv +++ b/libcxx/docs/Status/Cxx20Issues.csv @@ -102,7 +102,7 @@ "`2943 <https://wg21.link/LWG2943>`__","Problematic specification of the wide version of ``basic_filebuf::open``\ ","San Diego","|Nothing To Do|","" "`2960 <https://wg21.link/LWG2960>`__","[fund.ts.v3] ``nonesuch``\ is insufficiently useless","San Diego","|Complete|","" "`2995 <https://wg21.link/LWG2995>`__","``basic_stringbuf``\ default constructor forbids it from using SSO capacity","San Diego","","" -"`2996 <https://wg21.link/LWG2996>`__","Missing rvalue overloads for ``shared_ptr``\ operations","San Diego","","" +"`2996 <https://wg21.link/LWG2996>`__","Missing rvalue overloads for ``shared_ptr``\ operations","San Diego","|Complete|","17.0" "`3008 <https://wg21.link/LWG3008>`__","``make_shared``\ (sub)object destruction semantics are not specified","San Diego","|Complete|","16.0" "`3022 <https://wg21.link/LWG3022>`__","``is_convertible<derived*, base*>``\ may lead to ODR","San Diego","Resolved by 1285R0","" "`3025 <https://wg21.link/LWG3025>`__","Map-like container deduction guides should use ``pair<Key, T>``\ , not ``pair<const Key, T>``\ ","San Diego","|Complete|","" diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h index 28f0260..dce44a7 100644 --- a/libcxx/include/__memory/shared_ptr.h +++ b/libcxx/include/__memory/shared_ptr.h @@ -644,6 +644,18 @@ public: __cntrl_->__add_shared(); } +// LWG-2996 +// We don't backport because it is an evolutionary change. +#if _LIBCPP_STD_VER >= 20 + template <class _Yp> + _LIBCPP_HIDE_FROM_ABI shared_ptr(shared_ptr<_Yp>&& __r, element_type* __p) noexcept + : __ptr_(__p), + __cntrl_(__r.__cntrl_) { + __r.__ptr_ = nullptr; + __r.__cntrl_ = nullptr; + } +#endif + _LIBCPP_HIDE_FROM_ABI shared_ptr(const shared_ptr& __r) _NOEXCEPT : __ptr_(__r.__ptr_), @@ -1519,6 +1531,15 @@ static_pointer_cast(const shared_ptr<_Up>& __r) _NOEXCEPT typename shared_ptr<_Tp>::element_type*>(__r.get())); } +// LWG-2996 +// We don't backport because it is an evolutionary change. +#if _LIBCPP_STD_VER >= 20 +template <class _Tp, class _Up> +_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> static_pointer_cast(shared_ptr<_Up>&& __r) noexcept { + return shared_ptr<_Tp>(std::move(__r), static_cast<typename shared_ptr<_Tp>::element_type*>(__r.get())); +} +#endif + template<class _Tp, class _Up> inline _LIBCPP_INLINE_VISIBILITY shared_ptr<_Tp> @@ -1529,6 +1550,16 @@ dynamic_pointer_cast(const shared_ptr<_Up>& __r) _NOEXCEPT return __p ? shared_ptr<_Tp>(__r, __p) : shared_ptr<_Tp>(); } +// LWG-2996 +// We don't backport because it is an evolutionary change. +#if _LIBCPP_STD_VER >= 20 +template <class _Tp, class _Up> +_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> dynamic_pointer_cast(shared_ptr<_Up>&& __r) noexcept { + auto* __p = dynamic_cast<typename shared_ptr<_Tp>::element_type*>(__r.get()); + return __p ? shared_ptr<_Tp>(std::move(__r), __p) : shared_ptr<_Tp>(); +} +#endif + template<class _Tp, class _Up> _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> const_pointer_cast(const shared_ptr<_Up>& __r) _NOEXCEPT @@ -1537,6 +1568,15 @@ const_pointer_cast(const shared_ptr<_Up>& __r) _NOEXCEPT return shared_ptr<_Tp>(__r, const_cast<_RTp*>(__r.get())); } +// LWG-2996 +// We don't backport because it is an evolutionary change. +#if _LIBCPP_STD_VER >= 20 +template <class _Tp, class _Up> +_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> const_pointer_cast(shared_ptr<_Up>&& __r) noexcept { + return shared_ptr<_Tp>(std::move(__r), const_cast<typename shared_ptr<_Tp>::element_type*>(__r.get())); +} +#endif + template<class _Tp, class _Up> _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> reinterpret_pointer_cast(const shared_ptr<_Up>& __r) _NOEXCEPT @@ -1546,6 +1586,15 @@ reinterpret_pointer_cast(const shared_ptr<_Up>& __r) _NOEXCEPT typename shared_ptr<_Tp>::element_type*>(__r.get())); } +// LWG-2996 +// We don't backport because it is an evolutionary change. +#if _LIBCPP_STD_VER >= 20 +template <class _Tp, class _Up> +_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> reinterpret_pointer_cast(shared_ptr<_Up>&& __r) noexcept { + return shared_ptr<_Tp>(std::move(__r), reinterpret_cast<typename shared_ptr<_Tp>::element_type*>(__r.get())); +} +#endif + #ifndef _LIBCPP_HAS_NO_RTTI template<class _Dp, class _Tp> diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cast/const_pointer_cast.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cast/const_pointer_cast.pass.cpp index d0da8c1..9046b33 100644 --- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cast/const_pointer_cast.pass.cpp +++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cast/const_pointer_cast.pass.cpp @@ -10,11 +10,13 @@ // shared_ptr -// template<class T, class U> shared_ptr<T> const_pointer_cast(const shared_ptr<U>& r); +// template<class T, class U> shared_ptr<T> const_pointer_cast(const shared_ptr<U>& r) noexcept; +// template<class T, class U> shared_ptr<T> const_pointer_cast(shared_ptr<U>&& r) noexcept; +#include <cassert> #include <memory> #include <type_traits> -#include <cassert> +#include <utility> #include "test_macros.h" @@ -45,6 +47,7 @@ int main(int, char**) { { const std::shared_ptr<const A> pA(new A); + ASSERT_NOEXCEPT(std::const_pointer_cast<A>(pA)); std::shared_ptr<A> pB = std::const_pointer_cast<A>(pA); assert(pB.get() == pA.get()); assert(!pB.owner_before(pA) && !pA.owner_before(pB)); @@ -63,6 +66,17 @@ int main(int, char**) assert(!pB.owner_before(pA) && !pA.owner_before(pB)); } #endif // TEST_STD_VER > 14 +#if TEST_STD_VER > 20 + { + A* pA_raw = new A; + std::shared_ptr<const A> pA(pA_raw); + ASSERT_NOEXCEPT(std::const_pointer_cast<A>(std::move(pA))); + std::shared_ptr<A> pB = std::const_pointer_cast<A>(std::move(pA)); + assert(pA.get() == nullptr); + assert(pB.get() == pA_raw); + assert(pB.use_count() == 1); + } +#endif // TEST_STD_VER > 20 return 0; } diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cast/dynamic_pointer_cast.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cast/dynamic_pointer_cast.pass.cpp index 7a8041e..ae65859 100644 --- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cast/dynamic_pointer_cast.pass.cpp +++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cast/dynamic_pointer_cast.pass.cpp @@ -10,13 +10,15 @@ // shared_ptr -// template<class T, class U> shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& r); +// template<class T, class U> shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& r) noexcept; +// template<class T, class U> shared_ptr<T> dynamic_pointer_cast(shared_ptr<U>&& r) noexcept; // UNSUPPORTED: no-rtti +#include <cassert> #include <memory> #include <type_traits> -#include <cassert> +#include <utility> #include "test_macros.h" @@ -47,6 +49,7 @@ int main(int, char**) { { const std::shared_ptr<B> pB(new A); + ASSERT_NOEXCEPT(std::dynamic_pointer_cast<A>(pB)); std::shared_ptr<A> pA = std::dynamic_pointer_cast<A>(pB); assert(pA.get() == pB.get()); assert(!pB.owner_before(pA) && !pA.owner_before(pB)); @@ -65,6 +68,17 @@ int main(int, char**) assert(pA.use_count() == 0); } #endif // TEST_STD_VER > 14 +#if TEST_STD_VER > 20 + { + A* pA_raw = new A; + std::shared_ptr<B> pB(pA_raw); + ASSERT_NOEXCEPT(std::dynamic_pointer_cast<A>(std::move(pB))); + std::shared_ptr<A> pA = std::dynamic_pointer_cast<A>(std::move(pB)); + assert(pB.get() == nullptr); + assert(pA.get() == pA_raw); + assert(pA.use_count() == 1); + } +#endif // TEST_STD_VER > 20 return 0; } diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cast/reinterpret_pointer_cast.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cast/reinterpret_pointer_cast.pass.cpp index 743d60c..dccfd40 100644 --- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cast/reinterpret_pointer_cast.pass.cpp +++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cast/reinterpret_pointer_cast.pass.cpp @@ -12,12 +12,15 @@ // template<class T, class U> // shared_ptr<T> reinterpret_pointer_cast(const shared_ptr<U>& r) noexcept; +// template<class T, class U> +// shared_ptr<T> reinterpret_pointer_cast(shared_ptr<U>&& r) noexcept; #include "test_macros.h" +#include <cassert> #include <memory> #include <type_traits> -#include <cassert> +#include <utility> struct A { int x; @@ -29,6 +32,7 @@ struct Derived : public Base { }; int main(int, char**) { { const std::shared_ptr<A> pA(new A); + ASSERT_NOEXCEPT(std::reinterpret_pointer_cast<int>(pA)); std::shared_ptr<int> pi = std::reinterpret_pointer_cast<int>(pA); std::shared_ptr<A> pA2 = std::reinterpret_pointer_cast<A>(pi); assert(pA2.get() == pA.get()); @@ -70,6 +74,20 @@ int main(int, char**) { assert(!pi.owner_before(pA) && !pA.owner_before(pi)); } #endif // TEST_STD_VER > 14 +#if TEST_STD_VER > 20 + { + A* pA_raw = new A; + std::shared_ptr<A> pA(pA_raw); + ASSERT_NOEXCEPT(std::reinterpret_pointer_cast<int>(std::move(pA))); + std::shared_ptr<int> pi = std::reinterpret_pointer_cast<int>(std::move(pA)); + assert(pA.get() == nullptr); + assert(pi.use_count() == 1); + std::shared_ptr<A> pA2 = std::reinterpret_pointer_cast<A>(std::move(pi)); + assert(pi.get() == nullptr); + assert(pA2.get() == pA_raw); + assert(pA2.use_count() == 1); + } +#endif // TEST_STD_VER > 20 return 0; } diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cast/static_pointer_cast.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cast/static_pointer_cast.pass.cpp index 6449f72..ebf9d7c 100644 --- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cast/static_pointer_cast.pass.cpp +++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.cast/static_pointer_cast.pass.cpp @@ -10,11 +10,13 @@ // shared_ptr -// template<class T, class U> shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r); +// template<class T, class U> shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r) noexcept; +// template<class T, class U> shared_ptr<T> static_pointer_cast(shared_ptr<U>&& r) noexcept; +#include <cassert> #include <memory> #include <type_traits> -#include <cassert> +#include <utility> #include "test_macros.h" @@ -45,6 +47,7 @@ int main(int, char**) { { const std::shared_ptr<A> pA(new A); + ASSERT_NOEXCEPT(std::static_pointer_cast<B>(pA)); std::shared_ptr<B> pB = std::static_pointer_cast<B>(pA); assert(pB.get() == pA.get()); assert(!pB.owner_before(pA) && !pA.owner_before(pB)); @@ -81,6 +84,17 @@ int main(int, char**) assert(!pB.owner_before(pA) && !pA.owner_before(pB)); } #endif // TEST_STD_VER > 14 +#if TEST_STD_VER > 20 + { + A* pA_raw = new A; + std::shared_ptr<A> pA(pA_raw); + ASSERT_NOEXCEPT(std::static_pointer_cast<B>(std::move(pA))); + std::shared_ptr<B> pB = std::static_pointer_cast<B>(std::move(pA)); + assert(pA.get() == nullptr); + assert(pB.get() == pA_raw); + assert(pB.use_count() == 1); + } +#endif // TEST_STD_VER > 20 return 0; } diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/shared_ptr_pointer.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/shared_ptr_pointer.pass.cpp index 4c66312..e0b1e51 100644 --- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/shared_ptr_pointer.pass.cpp +++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/shared_ptr_pointer.pass.cpp @@ -96,23 +96,23 @@ int main(int, char**) } #if TEST_STD_VER > 17 && defined(_LIBCPP_VERSION) - // This won't pass when LWG-2996 is implemented. { std::shared_ptr<A> pA(new A); assert(pA.use_count() == 1); +# if TEST_STD_VER >= 20 + // LWG-2996 is only implemented in c++20 and beyond. + // We don't backport because it is an evolutionary change. { B b; std::shared_ptr<B> pB(std::move(pA), &b); assert(A::count == 1); assert(B::count == 1); - assert(pA.use_count() == 2); - assert(pB.use_count() == 2); + assert(pA.use_count() == 0); + assert(pB.use_count() == 1); assert(pB.get() == &b); } - assert(pA.use_count() == 1); - assert(A::count == 1); - assert(B::count == 0); +# endif // TEST_STD_VER > 20 } assert(A::count == 0); assert(B::count == 0); |