Fixes LWG issue 2875.
Differential Revision: https://reviews.llvm.org/D81414
"`2872 <https://wg21.link/LWG2872>`__","Add definition for direct-non-list-initialization","Kona","|Complete|",""
"`2873 <https://wg21.link/LWG2873>`__","Add noexcept to several shared_ptr related functions","Kona","|Complete|",""
"`2874 <https://wg21.link/LWG2874>`__","Constructor ``shared_ptr::shared_ptr(Y*)``\ should be constrained","Kona","",""
-"`2875 <https://wg21.link/LWG2875>`__","shared_ptr::shared_ptr(Y\*, D, [|hellip|\ ]) constructors should be constrained","Kona","",""
+"`2875 <https://wg21.link/LWG2875>`__","shared_ptr::shared_ptr(Y\*, D, [|hellip|\ ]) constructors should be constrained","Kona","|Complete|",""
"`2876 <https://wg21.link/LWG2876>`__","``shared_ptr::shared_ptr(const weak_ptr<Y>&)``\ constructor should be constrained","Kona","",""
"`2878 <https://wg21.link/LWG2878>`__","Missing DefaultConstructible requirement for istream_iterator default constructor","Kona","|Complete|",""
"`2890 <https://wg21.link/LWG2890>`__","The definition of 'object state' applies only to class types","Kona","|Complete|",""
: is_convertible<_Tp*, _Up*> {};
#endif // _LIBCPP_STD_VER > 14
+template <class _Dp, class _Pt,
+ class = decltype(_VSTD::declval<_Dp>()(_VSTD::declval<_Pt>()))>
+static true_type __well_formed_deleter_test(int);
+
+template <class, class>
+static false_type __well_formed_deleter_test(...);
+
+template <class _Dp, class _Pt>
+struct __well_formed_deleter : decltype(__well_formed_deleter_test<_Dp, _Pt>(0)) {};
+
+template<class _Dp, class _Tp, class _Yp>
+struct __shared_ptr_deleter_ctor_reqs
+{
+ static const bool value = __compatible_with<_Tp, _Yp>::value &&
+ is_move_constructible<_Dp>::value &&
+ __well_formed_deleter<_Dp, _Tp*>::value;
+};
+
#if defined(_LIBCPP_ABI_ENABLE_SHARED_PTR_TRIVIAL_ABI)
# define _LIBCPP_SHARED_PTR_TRIVIAL_ABI __attribute__((trivial_abi))
#else
typename enable_if<__compatible_with<_Yp, element_type>::value, __nat>::type = __nat());
template<class _Yp, class _Dp>
shared_ptr(_Yp* __p, _Dp __d,
- typename enable_if<__compatible_with<_Yp, element_type>::value, __nat>::type = __nat());
+ typename enable_if<__shared_ptr_deleter_ctor_reqs<_Dp, _Yp, element_type>::value, __nat>::type = __nat());
template<class _Yp, class _Dp, class _Alloc>
shared_ptr(_Yp* __p, _Dp __d, _Alloc __a,
- typename enable_if<__compatible_with<_Yp, element_type>::value, __nat>::type = __nat());
+ typename enable_if<__shared_ptr_deleter_ctor_reqs<_Dp, _Yp, element_type>::value, __nat>::type = __nat());
template <class _Dp> shared_ptr(nullptr_t __p, _Dp __d);
template <class _Dp, class _Alloc> shared_ptr(nullptr_t __p, _Dp __d, _Alloc __a);
template<class _Yp> _LIBCPP_INLINE_VISIBILITY shared_ptr(const shared_ptr<_Yp>& __r, element_type* __p) _NOEXCEPT;
template<class _Tp>
template<class _Yp, class _Dp>
shared_ptr<_Tp>::shared_ptr(_Yp* __p, _Dp __d,
- typename enable_if<__compatible_with<_Yp, element_type>::value, __nat>::type)
+ typename enable_if<__shared_ptr_deleter_ctor_reqs<_Dp, _Yp, element_type>::value, __nat>::type)
: __ptr_(__p)
{
#ifndef _LIBCPP_NO_EXCEPTIONS
template<class _Tp>
template<class _Yp, class _Dp, class _Alloc>
shared_ptr<_Tp>::shared_ptr(_Yp* __p, _Dp __d, _Alloc __a,
- typename enable_if<__compatible_with<_Yp, element_type>::value, __nat>::type)
+ typename enable_if<__shared_ptr_deleter_ctor_reqs<_Dp, _Yp, element_type>::value, __nat>::type)
: __ptr_(__p)
{
#ifndef _LIBCPP_NO_EXCEPTIONS
SPtr<2> s2(getFn<2>(), Deleter{}); // OK
SPtr<3> s3(nullptr, Deleter{}); // OK
}
- // expected-error-re@memory:* 2 {{static_assert failed{{.*}} "default_delete cannot be instantiated for function types"}}
- {
- SPtr<4> s4(getFn<4>()); // expected-note {{requested here}}
- SPtr<5> s5(getFn<5>(), std::default_delete<FnType<5>>{}); // expected-note {{requested here}}
- }
+
+ // expected-error-re@memory:* {{static_assert failed{{.*}} "default_delete cannot be instantiated for function types"}}
+ std::default_delete<FnType<5>> deleter{}; // expected-note {{requested here}}
return 0;
}
int A::count = 0;
+struct bad_ty { };
+
+struct bad_deleter
+{
+ void operator()(bad_ty) { }
+};
+
+struct no_move_deleter
+{
+ no_move_deleter(no_move_deleter const&) = delete;
+ no_move_deleter(no_move_deleter &&) = delete;
+ void operator()(int*) { }
+};
+
+static_assert(!std::is_move_constructible<no_move_deleter>::value, "");
+
struct Base { };
struct Derived : Base { };
assert(test_deleter<A>::dealloc_count == 1);
{
+ // Make sure we can't construct with:
+ // a) a deleter that doesn't have an operator ()(int*)
+ // b) a deleter that doesn't have a move constructor.
+ static_assert(!std::is_constructible<std::shared_ptr<int>, int*, bad_deleter>::value, "");
+ static_assert(!std::is_constructible<std::shared_ptr<int>, int*, no_move_deleter>::value, "");
+
// Make sure that we can construct a shared_ptr where the element type and pointer type
// aren't "convertible" but are "compatible".
static_assert(!std::is_constructible<std::shared_ptr<Derived[4]>, Base[4], test_deleter<Derived[4]> >::value, "");
int A::count = 0;
+struct bad_ty { };
+
+struct bad_deleter
+{
+ void operator()(bad_ty) { }
+};
+
+struct no_move_deleter
+{
+ no_move_deleter(no_move_deleter const&) = delete;
+ no_move_deleter(no_move_deleter &&) = delete;
+ void operator()(int*) { }
+};
+
+static_assert(!std::is_move_constructible<no_move_deleter>::value, "");
+
struct Base { };
struct Derived : Base { };
#endif // TEST_STD_VER >= 11
{
+ // Make sure we can't construct with:
+ // a) a deleter that doesn't have an operator ()(int*)
+ // b) a deleter that doesn't have a move constructor.
+ static_assert(!std::is_constructible<std::shared_ptr<int>, int*, bad_deleter,
+ test_allocator<A> >::value, "");
+ static_assert(!std::is_constructible<std::shared_ptr<int>, int*, no_move_deleter,
+ test_allocator<A> >::value, "");
+
// Make sure that we can construct a shared_ptr where the element type and pointer type
// aren't "convertible" but are "compatible".
static_assert(!std::is_constructible<std::shared_ptr<Derived[4]>,