[gcc(refs/vendors/redhat/heads/gcc-8-branch)] libstdc++: Fix regressions in unique_ptr::swap (PR 93562)

Jakub Jelinek jakub@gcc.gnu.org
Thu Sep 17 16:48:10 GMT 2020


https://gcc.gnu.org/g:323f78acc6fb690646d1925f9a8d6ede123e9a47

commit 323f78acc6fb690646d1925f9a8d6ede123e9a47
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Feb 26 15:04:53 2020 +0000

    libstdc++: Fix regressions in unique_ptr::swap (PR 93562)
    
    The requirements for this function are only that the deleter is
    swappable, but we incorrectly require that the element type is complete
    and that the deleter can be swapped using std::swap (which requires it
    to be move cosntructible and move assignable).
    
    The fix is to add __uniq_ptr_impl::swap which swaps the pointer and
    deleter individually, instead of using the generic std::swap on the
    tuple containing them.
    
            PR libstdc++/93562
            * include/bits/unique_ptr.h (__uniq_ptr_impl::swap): Define.
            (unique_ptr::swap, unique_ptr<T[], D>::swap): Call it.
            * testsuite/20_util/unique_ptr/modifiers/93562.cc: New test.

Diff:
---
 libstdc++-v3/ChangeLog                             | 10 +++
 libstdc++-v3/include/bits/unique_ptr.h             | 16 +++-
 .../20_util/unique_ptr/modifiers/93562.cc          | 98 ++++++++++++++++++++++
 3 files changed, 120 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 175107b5b30..c4203dfb93c 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,13 @@
+2020-02-26  Jonathan Wakely  <jwakely@redhat.com>
+
+	Backport from mainline
+	2020-02-04  Jonathan Wakely  <jwakely@redhat.com>
+
+	PR libstdc++/93562
+	* include/bits/unique_ptr.h (__uniq_ptr_impl::swap): Define.
+	(unique_ptr::swap, unique_ptr<T[], D>::swap): Call it.
+	* testsuite/20_util/unique_ptr/modifiers/93562.cc: New test.
+
 2020-02-26  Jonathan Wakely  <jwakely@redhat.com>
 
 	Backport from mainline
diff --git a/libstdc++-v3/include/bits/unique_ptr.h b/libstdc++-v3/include/bits/unique_ptr.h
index 90adf536cef..5efd75da506 100644
--- a/libstdc++-v3/include/bits/unique_ptr.h
+++ b/libstdc++-v3/include/bits/unique_ptr.h
@@ -151,6 +151,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _Dp&       _M_deleter() { return std::get<1>(_M_t); }
       const _Dp& _M_deleter() const { return std::get<1>(_M_t); }
 
+      void
+      swap(__uniq_ptr_impl& __rhs) noexcept
+      {
+	using std::swap;
+	swap(this->_M_ptr(), __rhs._M_ptr());
+	swap(this->_M_deleter(), __rhs._M_deleter());
+      }
+
     private:
       tuple<pointer, _Dp> _M_t;
     };
@@ -381,8 +389,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       void
       swap(unique_ptr& __u) noexcept
       {
-	using std::swap;
-	swap(_M_t, __u._M_t);
+	static_assert(__is_swappable<_Dp>::value, "deleter must be swappable");
+	_M_t.swap(__u._M_t);
       }
 
       // Disable copy from lvalue.
@@ -651,8 +659,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       void
       swap(unique_ptr& __u) noexcept
       {
-	using std::swap;
-	swap(_M_t, __u._M_t);
+	static_assert(__is_swappable<_Dp>::value, "deleter must be swappable");
+	_M_t.swap(__u._M_t);
       }
 
       // Disable copy from lvalue.
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/93562.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/93562.cc
new file mode 100644
index 00000000000..8ed236333ac
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/93562.cc
@@ -0,0 +1,98 @@
+// Copyright (C) 2020 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/>.
+
+// { dg-do run { target c++11 } }
+
+#include <memory>
+#include <testsuite_hooks.h>
+
+struct incomplete;
+
+// This function isn't called, we just need to check it compiles.
+void
+test01(std::unique_ptr<incomplete>& p1, std::unique_ptr<incomplete>& p2)
+{
+  // PR libstdc++/93562
+  p1.swap(p2);
+  swap(p1, p2);
+}
+
+// This function isn't called, we just need to check it compiles.
+void
+test02(std::unique_ptr<incomplete[]>& p1, std::unique_ptr<incomplete[]>& p2)
+{
+  // PR libstdc++/93562
+  p1.swap(p2);
+  swap(p1, p2);
+}
+
+namespace A
+{
+  struct Deleter
+  {
+    Deleter& operator=(const Deleter&) = delete;
+
+    void operator()(int* p) const noexcept { delete p; }
+
+    // found by ADL
+    friend void swap(Deleter& lhs, Deleter& rhs) noexcept
+    { std::swap(lhs.id, rhs.id); }
+
+    int id;
+  };
+
+  static_assert(!std::is_move_assignable<Deleter>::value, "not assignable");
+#if __cplusplus >= 201703L
+  static_assert(std::is_swappable_v<Deleter>, "but swappable");
+#endif
+} // namespace A
+
+void
+test03()
+{
+  std::unique_ptr<int, A::Deleter> p1(new int(1), { -1 });
+  std::unique_ptr<int, A::Deleter> p2(new int(2), { -2 });
+  int* const pi1 = p1.get();
+  int* const pi2 = p2.get();
+  // This type must swappable even though the deleter is not move-assignable:
+  swap(p1, p2);
+  VERIFY(p1.get() == pi2);
+  VERIFY(p1.get_deleter().id == -2);
+  VERIFY(p2.get() == pi1);
+  VERIFY(p2.get_deleter().id == -1);
+}
+
+void
+test04()
+{
+  std::unique_ptr<int[], A::Deleter> p1(new int[1]{1}, { -1 });
+  std::unique_ptr<int[], A::Deleter> p2(new int[2]{2, 2}, { -2 });
+  int* const pi1 = p1.get();
+  int* const pi2 = p2.get();
+  // This type must swappable even though the deleter is not move-assignable:
+  swap(p1, p2);
+  VERIFY(p1.get() == pi2);
+  VERIFY(p1.get_deleter().id == -2);
+  VERIFY(p2.get() == pi1);
+  VERIFY(p2.get_deleter().id == -1);
+}
+
+int main()
+{
+  test03();
+  test04();
+}


More information about the Libstdc++-cvs mailing list