From 5edc0c15f1667cc2a5deb664b25c007b35d259f6 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely <jwakely@redhat.com> Date: Mon, 10 May 2021 20:46:38 +0100 Subject: [PATCH] libstdc++: Implement proposed resolution to LWG 3548 This has been tentatively approved by LWG. The deleter from a unique_ptr can be moved into the shared_ptr (at least, since LWG 2802). This uses std::forward<_Del>(__r.get_deleter()) not std::move(__r.get_deleter()) because we don't want to convert the deleter to an rvalue when _Del is an lvalue reference type. This also adds a missing is_move_constructible_v<D> constraint to the shared_ptr(unique_ptr<Y, D>&&) constructor, which is inherited from the shared_ptr(Y*, D) constructor due to the use of "equivalent to" in the specified effects. libstdc++-v3/ChangeLog: * include/bits/shared_ptr_base.h (__shared_count(unique_ptr&&)): Initialize a non-reference deleter from an rvalue, as per LWG 3548. (__shared_ptr::_UniqCompatible): Add missing constraint. * testsuite/20_util/shared_ptr/cons/lwg3548.cc: New test. * testsuite/20_util/shared_ptr/cons/unique_ptr_deleter.cc: Check constraints. --- libstdc++-v3/include/bits/shared_ptr_base.h | 13 +++++++++---- .../20_util/shared_ptr/cons/lwg3548.cc | 16 ++++++++++++++++ .../shared_ptr/cons/unique_ptr_deleter.cc | 17 ++++++++++++++++- 3 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/shared_ptr/cons/lwg3548.cc diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h index 71099afbf7a4..eb9ad23ba1e3 100644 --- a/libstdc++-v3/include/bits/shared_ptr_base.h +++ b/libstdc++-v3/include/bits/shared_ptr_base.h @@ -684,8 +684,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using _Alloc_traits = allocator_traits<_Alloc>; _Alloc __a; _Sp_cd_type* __mem = _Alloc_traits::allocate(__a, 1); + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3548. shared_ptr construction from unique_ptr should move + // (not copy) the deleter _Alloc_traits::construct(__a, __mem, __r.release(), - __r.get_deleter()); // non-throwing + std::forward<_Del>(__r.get_deleter())); _M_pi = __mem; } @@ -1070,9 +1073,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // 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<__and_< - __sp_compatible_with<_Yp*, _Tp*>, is_convertible<_Ptr, element_type*> - >::value, _Res>::type; + using _UniqCompatible = __enable_if_t<__and_< + __sp_compatible_with<_Yp*, _Tp*>, + is_convertible<_Ptr, element_type*>, + is_move_constructible<_Del> + >::value, _Res>; // Constraint for assignment from unique_ptr: template<typename _Yp, typename _Del> diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/lwg3548.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/lwg3548.cc new file mode 100644 index 000000000000..d6ec7b1d0578 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/lwg3548.cc @@ -0,0 +1,16 @@ +// { dg-do compile { target c++11 } } + +#include <memory> + +// LWG 3548 +// shared_ptr construction from unique_ptr should move (not copy) the deleter + +struct D +{ + D() { } + D(D&&) { } + void operator()(int* p) const { delete p; } +}; + +std::unique_ptr<int, D> u; +std::shared_ptr<int> s1(std::move(u)); diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/unique_ptr_deleter.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/unique_ptr_deleter.cc index f4cf3ddda2e4..d7ca51a4aa6e 100644 --- a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/unique_ptr_deleter.cc +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/unique_ptr_deleter.cc @@ -58,10 +58,25 @@ test02() VERIFY( D::count == 0 ); // LWG 2415 } +void +test03() +{ + struct D + { + D() = default; + D(const D&) = delete; // not copyable or movable + void operator()(int* p) const { delete p; } + }; + + using namespace std; + static_assert( ! is_constructible<shared_ptr<int>, unique_ptr<int, D>>(), + "Constraints: is_move_constructible_v<D> is true" ); +} + int main() { test01(); test02(); - return 0; + test03(); } -- GitLab