[libcxx] r300489 - Fix passing incorrectly value-category when constructing unique_ptr's deleter

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Mon Apr 17 13:20:28 PDT 2017


Author: ericwf
Date: Mon Apr 17 15:20:27 2017
New Revision: 300489

URL: http://llvm.org/viewvc/llvm-project?rev=300489&view=rev
Log:
Fix passing incorrectly value-category when constructing unique_ptr's deleter

Modified:
    libcxx/trunk/include/memory
    libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.pass.cpp

Modified: libcxx/trunk/include/memory
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/memory?rev=300489&r1=300488&r2=300489&view=diff
==============================================================================
--- libcxx/trunk/include/memory (original)
+++ libcxx/trunk/include/memory Mon Apr 17 15:20:27 2017
@@ -2734,7 +2734,7 @@ public:
   >
   _LIBCPP_INLINE_VISIBILITY
   unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept
-      : __ptr_(__u.release(), _VSTD::forward<deleter_type>(__u.get_deleter())) {
+      : __ptr_(__u.release(), _VSTD::forward<_Ep>(__u.get_deleter())) {
   }
 
   template <class _Up, class _Ep,

Modified: libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.pass.cpp?rev=300489&r1=300488&r2=300489&view=diff
==============================================================================
--- libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.pass.cpp Mon Apr 17 15:20:27 2017
@@ -19,6 +19,7 @@
 #include <cassert>
 
 #include "test_macros.h"
+#include "type_id.h"
 #include "unique_ptr_test_helper.h"
 
 template <int ID = 0>
@@ -33,9 +34,71 @@ struct GenericConvertingDeleter {
   void operator()(void*) const {}
 };
 
+template <class Templ, class Other>
+struct is_specialization;
+
+template <template <int> class Templ, int ID1, class Other>
+struct is_specialization<Templ<ID1>, Other> : std::false_type {};
+
+template <template <int> class Templ, int ID1, int ID2>
+struct is_specialization<Templ<ID1>, Templ<ID2> > : std::true_type {};
+
+template <class Templ, class Other>
+using EnableIfSpecialization = typename std::enable_if<
+    is_specialization<Templ, typename std::decay<Other>::type >::value
+  >::type;
+
+
+template <int ID>
+struct TrackingDeleter {
+  TrackingDeleter() : arg_type(&makeArgumentID<>()) {}
+
+  TrackingDeleter(TrackingDeleter const&)
+      : arg_type(&makeArgumentID<TrackingDeleter const&>()) {}
+
+  TrackingDeleter(TrackingDeleter&&)
+      : arg_type(&makeArgumentID<TrackingDeleter &&>()) {}
+
+  template <class T, class = EnableIfSpecialization<TrackingDeleter, T> >
+  TrackingDeleter(T&&) : arg_type(&makeArgumentID<T&&>()) {}
+
+  TrackingDeleter& operator=(TrackingDeleter const&) {
+    arg_type = &makeArgumentID<TrackingDeleter const&>();
+    return *this;
+  }
+
+  TrackingDeleter& operator=(TrackingDeleter &&) {
+    arg_type = &makeArgumentID<TrackingDeleter &&>();
+    return *this;
+  }
+
+  template <class T, class = EnableIfSpecialization<TrackingDeleter, T> >
+  TrackingDeleter& operator=(T&&) {
+    arg_type = &makeArgumentID<T&&>();
+    return *this;
+  }
+
+  void operator()(void*) const {}
+
+public:
+  TypeID const* reset() const {
+    TypeID const* tmp = arg_type;
+    arg_type = nullptr;
+    return tmp;
+  }
+
+  mutable TypeID const* arg_type;
+};
+
+
+template <class ExpectT, int ID>
+bool checkArg(TrackingDeleter<ID> const& d) {
+  return d.arg_type && *d.arg_type == makeArgumentID<ExpectT>();
+}
+
+
 template <bool IsArray>
 void test_sfinae() {
-#if TEST_STD_VER >= 11
   typedef typename std::conditional<IsArray, A[], A>::type VT;
 
   { // Test that different non-reference deleter types are allowed so long
@@ -80,13 +143,11 @@ void test_sfinae() {
     static_assert(std::is_constructible<U1, U5&&>::value, "");
     static_assert(std::is_constructible<U1, U6&&>::value, "");
   }
-#endif
 }
 
 
 template <bool IsArray>
 void test_noexcept() {
-#if TEST_STD_VER >= 11
   typedef typename std::conditional<IsArray, A[], A>::type VT;
   {
     typedef std::unique_ptr<const VT> APtr;
@@ -108,7 +169,39 @@ void test_noexcept() {
     typedef std::unique_ptr<VT, const NCConstDeleter<const VT>&> BPtr;
     static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, "");
   }
-#endif
+}
+
+
+template <bool IsArray>
+void test_deleter_value_category() {
+  typedef typename std::conditional<IsArray, A[], A>::type VT;
+  using TD1 = TrackingDeleter<1>;
+  using TD2 = TrackingDeleter<2>;
+  TD1 d1;
+  TD2 d2;
+
+  { // Test non-reference deleter conversions
+    using U1 = std::unique_ptr<VT, TD1 >;
+    using U2 = std::unique_ptr<VT, TD2 >;
+    U2 u2;
+    u2.get_deleter().reset();
+    U1 u1(std::move(u2));
+    assert(checkArg<TD2&&>(u1.get_deleter()));
+  }
+  { // Test assignment from non-const ref
+    using U1 = std::unique_ptr<VT, TD1 >;
+    using U2 = std::unique_ptr<VT, TD2& >;
+    U2 u2(nullptr, d2);
+    U1 u1(std::move(u2));
+    assert(checkArg<TD2&>(u1.get_deleter()));
+  }
+  { // Test assignment from const ref
+    using U1 = std::unique_ptr<VT, TD1 >;
+    using U2 = std::unique_ptr<VT, TD2 const& >;
+    U2 u2(nullptr, d2);
+    U1 u1(std::move(u2));
+    assert(checkArg<TD2 const&>(u1.get_deleter()));
+  }
 }
 
 
@@ -116,9 +209,11 @@ int main() {
   {
     test_sfinae</*IsArray*/false>();
     test_noexcept<false>();
+    test_deleter_value_category<false>();
   }
   {
     test_sfinae</*IsArray*/true>();
     test_noexcept<true>();
+    test_deleter_value_category<true>();
   }
 }




More information about the cfe-commits mailing list