mirror of
https://github.com/llvm-mirror/libcxx.git
synced 2025-10-24 03:32:35 +08:00
Fix passing incorrectly value-category when constructing unique_ptr's deleter
git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@300489 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -2734,7 +2734,7 @@ public:
|
|||||||
>
|
>
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept
|
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,
|
template <class _Up, class _Ep,
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include "test_macros.h"
|
#include "test_macros.h"
|
||||||
|
#include "type_id.h"
|
||||||
#include "unique_ptr_test_helper.h"
|
#include "unique_ptr_test_helper.h"
|
||||||
|
|
||||||
template <int ID = 0>
|
template <int ID = 0>
|
||||||
@@ -33,9 +34,71 @@ struct GenericConvertingDeleter {
|
|||||||
void operator()(void*) const {}
|
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>
|
template <bool IsArray>
|
||||||
void test_sfinae() {
|
void test_sfinae() {
|
||||||
#if TEST_STD_VER >= 11
|
|
||||||
typedef typename std::conditional<IsArray, A[], A>::type VT;
|
typedef typename std::conditional<IsArray, A[], A>::type VT;
|
||||||
|
|
||||||
{ // Test that different non-reference deleter types are allowed so long
|
{ // 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, U5&&>::value, "");
|
||||||
static_assert(std::is_constructible<U1, U6&&>::value, "");
|
static_assert(std::is_constructible<U1, U6&&>::value, "");
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <bool IsArray>
|
template <bool IsArray>
|
||||||
void test_noexcept() {
|
void test_noexcept() {
|
||||||
#if TEST_STD_VER >= 11
|
|
||||||
typedef typename std::conditional<IsArray, A[], A>::type VT;
|
typedef typename std::conditional<IsArray, A[], A>::type VT;
|
||||||
{
|
{
|
||||||
typedef std::unique_ptr<const VT> APtr;
|
typedef std::unique_ptr<const VT> APtr;
|
||||||
@@ -108,7 +169,39 @@ void test_noexcept() {
|
|||||||
typedef std::unique_ptr<VT, const NCConstDeleter<const VT>&> BPtr;
|
typedef std::unique_ptr<VT, const NCConstDeleter<const VT>&> BPtr;
|
||||||
static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, "");
|
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_sfinae</*IsArray*/false>();
|
||||||
test_noexcept<false>();
|
test_noexcept<false>();
|
||||||
|
test_deleter_value_category<false>();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
test_sfinae</*IsArray*/true>();
|
test_sfinae</*IsArray*/true>();
|
||||||
test_noexcept<true>();
|
test_noexcept<true>();
|
||||||
|
test_deleter_value_category<true>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user