[libcxx-commits] [libcxx] a38a465 - [libc++] fix `shared_ptr`'s incorrect constraints
via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Feb 11 11:44:59 PST 2023
Author: Hui
Date: 2023-02-11T19:44:38Z
New Revision: a38a4654ce4b1d2ae8a03797d2e520e415150492
URL: https://github.com/llvm/llvm-project/commit/a38a4654ce4b1d2ae8a03797d2e520e415150492
DIFF: https://github.com/llvm/llvm-project/commit/a38a4654ce4b1d2ae8a03797d2e520e415150492.diff
LOG: [libc++] fix `shared_ptr`'s incorrect constraints
Fix several bugs:
1. https://llvm.org/PR60258
The conversion constructors' constraint `__compatible_with` incorrectly allow array types conversion to scalar types
2. https://llvm.org/PR53368
The constructor that takes `unique_ptr` are not suffiently constrained.
3. The constructors that take raw pointers incorretly use `__compatible_with`. They have different constraints
Differential Revision: https://reviews.llvm.org/D143346
Added:
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_helper.h
Modified:
libcxx/include/__memory/shared_ptr.h
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/unique_ptr_Y.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/shared_ptr_Y.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/shared_ptr_Y_rv.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/unique_ptr.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/weak_ptr.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer_deleter.pass.cpp
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer_deleter_allocator.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h
index 1c99686c4e5f3..b4798c6b31cff 100644
--- a/libcxx/include/__memory/shared_ptr.h
+++ b/libcxx/include/__memory/shared_ptr.h
@@ -367,13 +367,57 @@ class _LIBCPP_TEMPLATE_VIS allocator<__shared_ptr_dummy_rebind_allocator_type>
template<class _Tp> class _LIBCPP_TEMPLATE_VIS enable_shared_from_this;
-template<class _Tp, class _Up>
+// http://eel.is/c++draft/util.sharedptr#util.smartptr.shared.general-6
+// A pointer type Y* is said to be compatible with a pointer type T*
+// when either Y* is convertible to T* or Y is U[N] and T is cv U[].
+#if _LIBCPP_STD_VER >= 17
+template <class _Yp, class _Tp>
+struct __bounded_convertible_to_unbounded : false_type {};
+
+template <class _Up, std::size_t _Np, class _Tp>
+struct __bounded_convertible_to_unbounded<_Up[_Np], _Tp>
+ : is_same<__remove_cv_t<_Tp>, _Up[]> {};
+
+template <class _Yp, class _Tp>
struct __compatible_with
-#if _LIBCPP_STD_VER > 14
- : is_convertible<remove_extent_t<_Tp>*, remove_extent_t<_Up>*> {};
+ : _Or<
+ is_convertible<_Yp*, _Tp*>,
+ __bounded_convertible_to_unbounded<_Yp, _Tp>
+ > {};
#else
- : is_convertible<_Tp*, _Up*> {};
-#endif // _LIBCPP_STD_VER > 14
+template <class _Yp, class _Tp>
+struct __compatible_with
+ : is_convertible<_Yp*, _Tp*> {};
+#endif // _LIBCPP_STD_VER >= 17
+
+// Constructors that take raw pointers have a
diff erent set of "compatible" constraints
+// http://eel.is/c++draft/util.sharedptr#util.smartptr.shared.const-9.1
+// - If T is an array type, then either T is U[N] and Y(*)[N] is convertible to T*,
+// or T is U[] and Y(*)[] is convertible to T*.
+// - If T is not an array type, then Y* is convertible to T*.
+#if _LIBCPP_STD_VER >= 17
+template <class _Yp, class _Tp, class = void>
+struct __raw_pointer_compatible_with : _And<
+ _Not<is_array<_Tp>>,
+ is_convertible<_Yp*, _Tp*>
+ > {};
+
+template <class _Yp, class _Up, std::size_t _Np>
+struct __raw_pointer_compatible_with<_Yp, _Up[_Np], __enable_if_t<
+ is_convertible<_Yp(*)[_Np], _Up(*)[_Np]>::value> >
+ : true_type {};
+
+template <class _Yp, class _Up>
+struct __raw_pointer_compatible_with<_Yp, _Up[], __enable_if_t<
+ is_convertible<_Yp(*)[], _Up(*)[]>::value> >
+ : true_type {};
+
+#else
+template <class _Yp, class _Tp>
+struct __raw_pointer_compatible_with
+ : is_convertible<_Yp*, _Tp*> {};
+#endif // _LIBCPP_STD_VER >= 17
+
template <class _Ptr, class = void>
struct __is_deletable : false_type { };
@@ -395,12 +439,12 @@ static false_type __well_formed_deleter_test(...);
template <class _Dp, class _Pt>
struct __well_formed_deleter : decltype(std::__well_formed_deleter_test<_Dp, _Pt>(0)) {};
-template<class _Dp, class _Tp, class _Yp>
+template<class _Dp, class _Yp, class _Tp>
struct __shared_ptr_deleter_ctor_reqs
{
- static const bool value = __compatible_with<_Tp, _Yp>::value &&
+ static const bool value = __raw_pointer_compatible_with<_Yp, _Tp>::value &&
is_move_constructible<_Dp>::value &&
- __well_formed_deleter<_Dp, _Tp*>::value;
+ __well_formed_deleter<_Dp, _Yp*>::value;
};
#if defined(_LIBCPP_ABI_ENABLE_SHARED_PTR_TRIVIAL_ABI)
@@ -439,7 +483,7 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr
template<class _Yp, class = __enable_if_t<
_And<
- __compatible_with<_Yp, _Tp>
+ __raw_pointer_compatible_with<_Yp, _Tp>
// In C++03 we get errors when trying to do SFINAE with the
// delete operator, so we always pretend that it's deletable.
// The same happens on GCC.
@@ -457,7 +501,7 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr
__enable_weak_this(__p, __p);
}
- template<class _Yp, class _Dp, class = __enable_if_t<__shared_ptr_deleter_ctor_reqs<_Dp, _Yp, element_type>::value> >
+ template<class _Yp, class _Dp, class = __enable_if_t<__shared_ptr_deleter_ctor_reqs<_Dp, _Yp, _Tp>::value> >
_LIBCPP_HIDE_FROM_ABI
shared_ptr(_Yp* __p, _Dp __d)
: __ptr_(__p)
@@ -484,7 +528,7 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr
#endif // _LIBCPP_NO_EXCEPTIONS
}
- template<class _Yp, class _Dp, class _Alloc, class = __enable_if_t<__shared_ptr_deleter_ctor_reqs<_Dp, _Yp, element_type>::value> >
+ template<class _Yp, class _Dp, class _Alloc, class = __enable_if_t<__shared_ptr_deleter_ctor_reqs<_Dp, _Yp, _Tp>::value> >
_LIBCPP_HIDE_FROM_ABI
shared_ptr(_Yp* __p, _Dp __d, _Alloc __a)
: __ptr_(__p)
@@ -646,6 +690,7 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr
template <class _Yp, class _Dp, class = __enable_if_t<
!is_lvalue_reference<_Dp>::value &&
+ __compatible_with<_Yp, _Tp>::value &&
is_convertible<typename unique_ptr<_Yp, _Dp>::pointer, element_type*>::value
> >
_LIBCPP_HIDE_FROM_ABI
@@ -668,6 +713,7 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr
template <class _Yp, class _Dp, class = void, class = __enable_if_t<
is_lvalue_reference<_Dp>::value &&
+ __compatible_with<_Yp, _Tp>::value &&
is_convertible<typename unique_ptr<_Yp, _Dp>::pointer, element_type*>::value
> >
_LIBCPP_HIDE_FROM_ABI
@@ -740,9 +786,10 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr
}
#endif
- template <class _Yp, class _Dp, class = __enable_if_t<
- is_convertible<typename unique_ptr<_Yp, _Dp>::pointer, element_type*>::value
- > >
+ template <class _Yp, class _Dp, class = __enable_if_t<_And<
+ __compatible_with<_Yp, _Tp>,
+ is_convertible<typename unique_ptr<_Yp, _Dp>::pointer, element_type*>
+ >::value> >
_LIBCPP_HIDE_FROM_ABI
shared_ptr<_Tp>& operator=(unique_ptr<_Yp, _Dp>&& __r)
{
@@ -764,7 +811,7 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr
}
template<class _Yp, class = __enable_if_t<
- __compatible_with<_Yp, _Tp>::value
+ __raw_pointer_compatible_with<_Yp, _Tp>::value
> >
_LIBCPP_HIDE_FROM_ABI
void reset(_Yp* __p)
@@ -773,8 +820,7 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr
}
template<class _Yp, class _Dp, class = __enable_if_t<
- __compatible_with<_Yp, _Tp>::value
- > >
+ __shared_ptr_deleter_ctor_reqs<_Dp, _Yp, _Tp>::value> >
_LIBCPP_HIDE_FROM_ABI
void reset(_Yp* __p, _Dp __d)
{
@@ -782,8 +828,7 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr
}
template<class _Yp, class _Dp, class _Alloc, class = __enable_if_t<
- __compatible_with<_Yp, _Tp>::value
- > >
+ __shared_ptr_deleter_ctor_reqs<_Dp, _Yp, _Tp>::value> >
_LIBCPP_HIDE_FROM_ABI
void reset(_Yp* __p, _Dp __d, _Alloc __a)
{
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/unique_ptr_Y.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/unique_ptr_Y.pass.cpp
index 35671c41842f2..b5abcb6f04ceb 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/unique_ptr_Y.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.assign/unique_ptr_Y.pass.cpp
@@ -55,6 +55,16 @@ struct StatefulArrayDeleter {
}
};
+// https://llvm.org/PR53368
+// Bogus unique_ptr-to-shared_ptr conversions should be forbidden
+#if TEST_STD_VER >= 17
+static_assert( std::is_assignable<std::shared_ptr<A>&, std::unique_ptr<A>&&>::value, "");
+static_assert( std::is_assignable<std::shared_ptr<A[]>&, std::unique_ptr<A[]>&&>::value, "");
+static_assert(!std::is_assignable<std::shared_ptr<A>&, std::unique_ptr<A[]>&&>::value, "");
+static_assert(!std::is_assignable<std::shared_ptr<B[]>&, std::unique_ptr<A[]>&&>::value, "");
+static_assert(!std::is_assignable<std::shared_ptr<B>&, std::unique_ptr<A[]>&&>::value, "");
+#endif
+
int main(int, char**)
{
{
@@ -126,40 +136,6 @@ int main(int, char**)
assert(B::count == 0);
assert(A::count == 0);
-#ifdef _LIBCPP_VERSION // https://llvm.org/PR53368
- {
- std::unique_ptr<A[]> ptr(new A[8]);
- A* raw_ptr = ptr.get();
- std::shared_ptr<B> p;
- p = std::move(ptr);
- assert(A::count == 8);
- assert(B::count == 8);
- assert(p.use_count() == 1);
- assert(p.get() == raw_ptr);
- assert(ptr.get() == 0);
- }
- assert(A::count == 0);
- assert(B::count == 0);
-
- {
- std::unique_ptr<A[]> ptr(new A[8]);
- A* raw_ptr = ptr.get();
- std::shared_ptr<A> p;
- p = std::move(ptr);
- assert(A::count == 8);
- assert(p.use_count() == 1);
- assert(p.get() == raw_ptr);
- assert(ptr.get() == 0);
- }
- assert(A::count == 0);
-
- {
- std::unique_ptr<int[]> ptr(new int[8]);
- std::shared_ptr<int> p;
- p = std::move(ptr);
- }
-#endif // _LIBCPP_VERSION
-
#if TEST_STD_VER > 14
{
StatefulArrayDeleter<A> d;
@@ -172,22 +148,6 @@ int main(int, char**)
assert(A::count == 0);
assert(B::count == 0);
-#ifdef _LIBCPP_VERSION // https://llvm.org/PR53368
- {
- std::unique_ptr<A[]> ptr(new A[8]);
- A* raw_ptr = ptr.get();
- std::shared_ptr<B[]> p;
- p = std::move(ptr);
- assert(A::count == 8);
- assert(B::count == 8);
- assert(p.use_count() == 1);
- assert(p.get() == raw_ptr);
- assert(ptr.get() == 0);
- }
- assert(A::count == 0);
- assert(B::count == 0);
-#endif // _LIBCPP_VERSION
-
{
std::unique_ptr<A[]> ptr(new A[8]);
A* raw_ptr = ptr.get();
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer.pass.cpp
index ef3270efc8253..87b0cbde14a35 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer.pass.cpp
@@ -10,8 +10,9 @@
// template<class Y> explicit shared_ptr(Y* p);
-#include <memory>
#include <cassert>
+#include <memory>
+#include <type_traits>
#include "test_macros.h"
@@ -26,6 +27,25 @@ struct A
int A::count = 0;
+struct Derived : A {};
+
+// https://llvm.org/PR60258
+// Invalid constructor SFINAE for std::shared_ptr's array ctors
+static_assert( std::is_constructible<std::shared_ptr<int>, int*>::value, "");
+static_assert( std::is_constructible<std::shared_ptr<A>, Derived*>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<A>, int*>::value, "");
+
+#if TEST_STD_VER >= 17
+static_assert( std::is_constructible<std::shared_ptr<int[]>, int*>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[]>, int(*)[]>::value, "");
+static_assert( std::is_constructible<std::shared_ptr<int[5]>, int*>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[5]>, int(*)[5]>::value, "");
+#endif
+
+// Test explicit
+static_assert(std::is_constructible<std::shared_ptr<int>, int*>::value, "");
+static_assert(!std::is_convertible<int*, std::shared_ptr<int> >::value, "");
+
int main(int, char**)
{
{
@@ -71,11 +91,18 @@ int main(int, char**)
}
{
- assert(A::count == 0);
+ assert(A::count == 0);
std::shared_ptr<const A[]> pA(new A[8]);
assert(pA.use_count() == 1);
assert(A::count == 8);
}
+
+ {
+ assert(A::count == 0);
+ std::shared_ptr<A> pA(new Derived);
+ assert(pA.use_count() == 1);
+ assert(A::count == 1);
+ }
#endif
return 0;
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter.pass.cpp
index b3580e25fe52c..463130789416e 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter.pass.cpp
@@ -60,6 +60,22 @@ class MoveDeleter
void operator()(T *ptr) { delete ptr; }
};
+// https://llvm.org/PR60258
+// Invalid constructor SFINAE for std::shared_ptr's array ctors
+static_assert( std::is_constructible<std::shared_ptr<int>, int*, test_deleter<int> >::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int>, int*, bad_deleter>::value, "");
+static_assert( std::is_constructible<std::shared_ptr<Base>, Derived*, test_deleter<Base> >::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<A>, int*, test_deleter<A> >::value, "");
+
+#if TEST_STD_VER >= 17
+static_assert( std::is_constructible<std::shared_ptr<int[]>, int*, test_deleter<int>>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[]>, int*, bad_deleter>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[]>, int(*)[], test_deleter<int>>::value, "");
+static_assert( std::is_constructible<std::shared_ptr<int[5]>, int*, test_deleter<int>>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[5]>, int*, bad_deleter>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[5]>, int(*)[5], test_deleter<int>>::value, "");
+#endif
+
int main(int, char**)
{
{
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp
index 2fc25282230c8..6d66e05e426b4 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp
@@ -60,6 +60,23 @@ class MoveDeleter
void operator()(T *ptr) { delete ptr; }
};
+// https://llvm.org/PR60258
+// Invalid constructor SFINAE for std::shared_ptr's array ctors
+static_assert( std::is_constructible<std::shared_ptr<int>, int*, test_deleter<int>, test_allocator<int> >::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int>, int*, bad_deleter, test_allocator<int> >::value, "");
+static_assert( std::is_constructible<std::shared_ptr<Base>, Derived*, test_deleter<Base>, test_allocator<Base> >::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<A>, int*, test_deleter<A>, test_allocator<A> >::value, "");
+
+#if TEST_STD_VER >= 17
+static_assert( std::is_constructible<std::shared_ptr<int[]>, int*, test_deleter<int>, test_allocator<int>>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[]>, int*, bad_deleter, test_allocator<int>>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[]>, int(*)[], test_deleter<int>, test_allocator<int>>::value, "");
+static_assert( std::is_constructible<std::shared_ptr<int[5]>, int*, test_deleter<int>, test_allocator<int>>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[5]>, int*, bad_deleter, test_allocator<int>>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[5]>, int(*)[5], test_deleter<int>, test_allocator<int>>::value, "");
+#endif
+
+
int main(int, char**)
{
{
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/shared_ptr_Y.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/shared_ptr_Y.pass.cpp
index 26f381c9a2892..06817302446e8 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/shared_ptr_Y.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/shared_ptr_Y.pass.cpp
@@ -74,6 +74,23 @@ class private_delete_arr_op
}
};
+// https://llvm.org/PR60258
+// Invalid constructor SFINAE for std::shared_ptr's array ctors
+static_assert(!std::is_constructible<std::shared_ptr<int>, const std::shared_ptr<long>&>::value, "");
+static_assert( std::is_constructible<std::shared_ptr<B>, const std::shared_ptr<A>&>::value, "");
+static_assert( std::is_constructible<std::shared_ptr<const A>, const std::shared_ptr<A>&>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<A>, const std::shared_ptr<const A>&>::value, "");
+
+#if TEST_STD_VER >= 17
+static_assert(!std::is_constructible<std::shared_ptr<int>, const std::shared_ptr<int[]>&>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int>, const std::shared_ptr<int[5]>&>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[]>, const std::shared_ptr<int>&>::value, "");
+static_assert( std::is_constructible<std::shared_ptr<int[]>, const std::shared_ptr<int[5]>&>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[5]>, const std::shared_ptr<int>&>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[5]>, const std::shared_ptr<int[]>&>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[7]>, const std::shared_ptr<int[5]>&>::value, "");
+#endif
+
int main(int, char**)
{
static_assert(( std::is_convertible<std::shared_ptr<A>, std::shared_ptr<B> >::value), "");
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/shared_ptr_Y_rv.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/shared_ptr_Y_rv.pass.cpp
index 84ec26eb140ee..10ccbc4e7adea 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/shared_ptr_Y_rv.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/shared_ptr_Y_rv.pass.cpp
@@ -55,6 +55,23 @@ struct C
int C::count = 0;
+// https://llvm.org/PR60258
+// Invalid constructor SFINAE for std::shared_ptr's array ctors
+static_assert(!std::is_constructible<std::shared_ptr<int>, std::shared_ptr<long>&&>::value, "");
+static_assert( std::is_constructible<std::shared_ptr<B>, std::shared_ptr<A>&&>::value, "");
+static_assert( std::is_constructible<std::shared_ptr<const A>, std::shared_ptr<A>&&>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<A>, std::shared_ptr<const A>&&>::value, "");
+
+#if TEST_STD_VER >= 17
+static_assert(!std::is_constructible<std::shared_ptr<int>, std::shared_ptr<int[]>&&>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int>, std::shared_ptr<int[5]>&&>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[]>, std::shared_ptr<int>&&>::value, "");
+static_assert( std::is_constructible<std::shared_ptr<int[]>, std::shared_ptr<int[5]>&&>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[5]>, std::shared_ptr<int>&&>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[5]>, std::shared_ptr<int[]>&&>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[7]>, std::shared_ptr<int[5]>&&>::value, "");
+#endif
+
int main(int, char**)
{
static_assert(( std::is_convertible<std::shared_ptr<A>, std::shared_ptr<B> >::value), "");
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/unique_ptr.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/unique_ptr.pass.cpp
index 871aac6eae0f6..9308bb3858c65 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/unique_ptr.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/unique_ptr.pass.cpp
@@ -90,6 +90,16 @@ struct MovingDeleter {
int *moves_;
};
+// https://llvm.org/PR53368
+// Bogus unique_ptr-to-shared_ptr conversions should be forbidden
+#if TEST_STD_VER >= 17
+static_assert( std::is_constructible<std::shared_ptr<A>, std::unique_ptr<A>&&>::value, "");
+static_assert( std::is_constructible<std::shared_ptr<A[]>, std::unique_ptr<A[]>&&>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<A>, std::unique_ptr<A[]>&&>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<B[]>, std::unique_ptr<A[]>&&>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<B>, std::unique_ptr<A[]>&&>::value, "");
+#endif
+
int main(int, char**)
{
{
@@ -169,36 +179,6 @@ int main(int, char**)
}
assert(A::count == 0);
-#ifdef _LIBCPP_VERSION // https://llvm.org/PR53368
- {
- std::unique_ptr<A[]> ptr(new A[8]);
- A* raw_ptr = ptr.get();
- std::shared_ptr<B> p(std::move(ptr));
- assert(A::count == 8);
- assert(B::count == 8);
- assert(p.use_count() == 1);
- assert(p.get() == raw_ptr);
- assert(ptr.get() == 0);
- }
- assert(A::count == 0);
- assert(B::count == 0);
-
- {
- std::unique_ptr<A[]> ptr(new A[8]);
- A* raw_ptr = ptr.get();
- std::shared_ptr<A> p(std::move(ptr));
- assert(A::count == 8);
- assert(p.use_count() == 1);
- assert(p.get() == raw_ptr);
- assert(ptr.get() == 0);
- }
- assert(A::count == 0);
-
- {
- std::unique_ptr<int[]> ptr(new int[8]);
- std::shared_ptr<int> p(std::move(ptr));
- }
-#endif // _LIBCPP_VERSION
#if TEST_STD_VER > 14
{
@@ -211,21 +191,6 @@ int main(int, char**)
assert(A::count == 0);
assert(B::count == 0);
-#ifdef _LIBCPP_VERSION // https://llvm.org/PR53368
- {
- std::unique_ptr<A[]> ptr(new A[8]);
- A* raw_ptr = ptr.get();
- std::shared_ptr<B[]> p(std::move(ptr));
- assert(A::count == 8);
- assert(B::count == 8);
- assert(p.use_count() == 1);
- assert(p.get() == raw_ptr);
- assert(ptr.get() == 0);
- }
- assert(A::count == 0);
- assert(B::count == 0);
-#endif // _LIBCPP_VERSION
-
{
std::unique_ptr<A[]> ptr(new A[8]);
A* raw_ptr = ptr.get();
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/weak_ptr.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/weak_ptr.pass.cpp
index 57d7cc58ef68c..f59181343b910 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/weak_ptr.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/weak_ptr.pass.cpp
@@ -12,8 +12,9 @@
// template<class Y> explicit shared_ptr(const weak_ptr<Y>& r);
-#include <memory>
#include <cassert>
+#include <memory>
+#include <type_traits>
#include "test_macros.h"
@@ -40,6 +41,23 @@ struct A
int A::count = 0;
+// https://llvm.org/PR60258
+// Invalid constructor SFINAE for std::shared_ptr's array ctors
+static_assert(!std::is_constructible<std::shared_ptr<int>, const std::weak_ptr<long>&>::value, "");
+static_assert( std::is_constructible<std::shared_ptr<B>, const std::weak_ptr<A>&>::value, "");
+static_assert( std::is_constructible<std::shared_ptr<const A>, const std::weak_ptr<A>&>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<A>, const std::weak_ptr<const A>&>::value, "");
+
+#if TEST_STD_VER >= 17
+static_assert(!std::is_constructible<std::shared_ptr<int>, const std::weak_ptr<int[]>&>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int>, const std::weak_ptr<int[5]>&>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[]>, const std::weak_ptr<int>&>::value, "");
+static_assert( std::is_constructible<std::shared_ptr<int[]>, const std::weak_ptr<int[5]>&>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[5]>, const std::weak_ptr<int>&>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[5]>, const std::weak_ptr<int[]>&>::value, "");
+static_assert(!std::is_constructible<std::shared_ptr<int[7]>, const std::weak_ptr<int[5]>&>::value, "");
+#endif
+
int main(int, char**)
{
#ifndef TEST_HAS_NO_EXCEPTIONS
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_helper.h b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_helper.h
new file mode 100644
index 0000000000000..27d7264be172e
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_helper.h
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef TEST_STD_SHARED_PTR_RESET_H
+#define TEST_STD_SHARED_PTR_RESET_H
+
+#include <memory>
+#include <type_traits>
+
+template <class T, class... Args>
+std::false_type test_has_reset(...);
+
+template <class T, class... Args>
+typename std::enable_if<std::is_same<decltype(std::declval<T>().reset(std::declval<Args>()...)), void>::value,
+ std::true_type>::type
+test_has_reset(int);
+
+template <class T, class... Args>
+using HasReset = decltype(test_has_reset<T, Args...>(0));
+
+#endif // TEST_STD_SHARED_PTR_RESET_H
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer.pass.cpp
index d764e8a312d7a..d1d19e4562355 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer.pass.cpp
@@ -15,6 +15,7 @@
#include <memory>
#include <cassert>
+#include "reset_helper.h"
#include "test_macros.h"
struct B
@@ -40,6 +41,19 @@ struct A
int A::count = 0;
+struct Derived : A {};
+
+static_assert( HasReset<std::shared_ptr<int>, int*>::value, "");
+static_assert( HasReset<std::shared_ptr<A>, Derived*>::value, "");
+static_assert(!HasReset<std::shared_ptr<A>, int*>::value, "");
+
+#if TEST_STD_VER >= 17
+static_assert( HasReset<std::shared_ptr<int[]>, int*>::value, "");
+static_assert(!HasReset<std::shared_ptr<int[]>, int(*)[]>::value, "");
+static_assert( HasReset<std::shared_ptr<int[5]>, int*>::value, "");
+static_assert(!HasReset<std::shared_ptr<int[5]>, int(*)[5]>::value, "");
+#endif
+
int main(int, char**)
{
{
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer_deleter.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer_deleter.pass.cpp
index 14c336b4f59ca..d0375d3aa2001 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer_deleter.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer_deleter.pass.cpp
@@ -12,10 +12,11 @@
// template<class Y, class D> void reset(Y* p, D d);
-#include <memory>
#include <cassert>
-#include "test_macros.h"
+#include <memory>
#include "deleter_types.h"
+#include "reset_helper.h"
+#include "test_macros.h"
struct B
{
@@ -40,6 +41,29 @@ struct A
int A::count = 0;
+struct bad_ty { };
+struct bad_deleter
+{
+ void operator()(bad_ty) { }
+};
+
+struct Base { };
+struct Derived : Base { };
+
+static_assert( HasReset<std::shared_ptr<int>, int*, test_deleter<int> >::value, "");
+static_assert(!HasReset<std::shared_ptr<int>, int*, bad_deleter>::value, "");
+static_assert( HasReset<std::shared_ptr<Base>, Derived*, test_deleter<Base> >::value, "");
+static_assert(!HasReset<std::shared_ptr<A>, int*, test_deleter<A> >::value, "");
+
+#if TEST_STD_VER >= 17
+static_assert( HasReset<std::shared_ptr<int[]>, int*, test_deleter<int>>::value, "");
+static_assert(!HasReset<std::shared_ptr<int[]>, int*, bad_deleter>::value, "");
+static_assert(!HasReset<std::shared_ptr<int[]>, int(*)[], test_deleter<int>>::value, "");
+static_assert( HasReset<std::shared_ptr<int[5]>, int*, test_deleter<int>>::value, "");
+static_assert(!HasReset<std::shared_ptr<int[5]>, int*, bad_deleter>::value, "");
+static_assert(!HasReset<std::shared_ptr<int[5]>, int(*)[5], test_deleter<int>>::value, "");
+#endif
+
int main(int, char**)
{
{
diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer_deleter_allocator.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer_deleter_allocator.pass.cpp
index a6ea07ea37cee..1cd42c08a23ff 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer_deleter_allocator.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer_deleter_allocator.pass.cpp
@@ -12,10 +12,11 @@
// template<class Y, class D, class A> void reset(Y* p, D d, A a);
-#include <memory>
#include <cassert>
+#include <memory>
#include "test_macros.h"
#include "deleter_types.h"
+#include "reset_helper.h"
#include "test_allocator.h"
struct B
@@ -41,6 +42,30 @@ struct A
int A::count = 0;
+struct bad_ty { };
+
+struct bad_deleter
+{
+ void operator()(bad_ty) { }
+};
+
+struct Base { };
+struct Derived : Base { };
+
+static_assert( HasReset<std::shared_ptr<int>, int*, test_deleter<int>, test_allocator<int> >::value, "");
+static_assert(!HasReset<std::shared_ptr<int>, int*, bad_deleter, test_allocator<int> >::value, "");
+static_assert( HasReset<std::shared_ptr<Base>, Derived*, test_deleter<Base>, test_allocator<Base> >::value, "");
+static_assert(!HasReset<std::shared_ptr<A>, int*, test_deleter<A>, test_allocator<A> >::value, "");
+
+#if TEST_STD_VER >= 17
+static_assert( HasReset<std::shared_ptr<int[]>, int*, test_deleter<int>, test_allocator<int>>::value, "");
+static_assert(!HasReset<std::shared_ptr<int[]>, int*, bad_deleter, test_allocator<int>>::value, "");
+static_assert(!HasReset<std::shared_ptr<int[]>, int(*)[], test_deleter<int>, test_allocator<int>>::value, "");
+static_assert( HasReset<std::shared_ptr<int[5]>, int*, test_deleter<int>, test_allocator<int>>::value, "");
+static_assert(!HasReset<std::shared_ptr<int[5]>, int*, bad_deleter, test_allocator<int>>::value, "");
+static_assert(!HasReset<std::shared_ptr<int[5]>, int(*)[5], test_deleter<int>, test_allocator<int>>::value, "");
+#endif
+
int main(int, char**)
{
test_allocator_statistics alloc_stats;
More information about the libcxx-commits
mailing list