Fix passing incorrectly value-category when constructing unique_ptr's deleter
llvm-svn: 300489
Cr-Mirrored-From: sso://chromium.googlesource.com/_direct/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: 86321b2bc8350428d0b2eb81fff09d49098e9359
diff --git a/include/memory b/include/memory
index 44a0c34..87484a1 100644
--- a/include/memory
+++ b/include/memory
@@ -2734,7 +2734,7 @@
>
_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,
diff --git a/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.pass.cpp b/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.pass.cpp
index 6e5db86..769deea 100644
--- a/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.pass.cpp
+++ b/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.pass.cpp
@@ -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 @@
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 @@
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 @@
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 @@
{
test_sfinae</*IsArray*/false>();
test_noexcept<false>();
+ test_deleter_value_category<false>();
}
{
test_sfinae</*IsArray*/true>();
test_noexcept<true>();
+ test_deleter_value_category<true>();
}
}