]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Implement proposed resolution to LWG 3548
authorJonathan Wakely <jwakely@redhat.com>
Mon, 10 May 2021 19:46:38 +0000 (20:46 +0100)
committerJonathan Wakely <jwakely@redhat.com>
Tue, 11 May 2021 19:50:08 +0000 (20:50 +0100)
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.

(cherry picked from commit 5edc0c15f1667cc2a5deb664b25c007b35d259f6)

libstdc++-v3/include/bits/shared_ptr_base.h
libstdc++-v3/testsuite/20_util/shared_ptr/cons/lwg3548.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/shared_ptr/cons/unique_ptr_deleter.cc

index 71099afbf7a4ea07d55591075a6e6819b424348c..eb9ad23ba1e3d37a9230bfad048c0296066c9424 100644 (file)
@@ -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 (file)
index 0000000..d6ec7b1
--- /dev/null
@@ -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));
index f4cf3ddda2e466cb79b7174fc7b3eb6c799f3dee..d7ca51a4aa6e72641e974f4fee1bcece83b729be 100644 (file)
@@ -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();
 }