forked from OSchip/llvm-project
[libcxx] Fix LWG 2875: shared_ptr::shared_ptr(Y*, D, […]) constructors should be constrained.
Fixes LWG issue 2875. Differential Revision: https://reviews.llvm.org/D81414
This commit is contained in:
parent
513463fd26
commit
dbc89028d7
|
@ -300,7 +300,7 @@
|
|||
"`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|",""
|
||||
|
|
|
|
@ -2620,6 +2620,24 @@ struct __compatible_with
|
|||
: 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
|
||||
|
@ -2652,10 +2670,10 @@ public:
|
|||
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;
|
||||
|
@ -2921,7 +2939,7 @@ shared_ptr<_Tp>::shared_ptr(_Yp* __p,
|
|||
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
|
||||
|
@ -2975,7 +2993,7 @@ shared_ptr<_Tp>::shared_ptr(nullptr_t __p, _Dp __d)
|
|||
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
|
||||
|
|
|
@ -44,11 +44,9 @@ int main(int, char**) {
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,22 @@ struct A
|
|||
|
||||
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 { };
|
||||
|
||||
|
@ -65,6 +81,12 @@ int main(int, char**)
|
|||
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, "");
|
||||
|
|
|
@ -28,6 +28,22 @@ struct A
|
|||
|
||||
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 { };
|
||||
|
||||
|
@ -115,6 +131,14 @@ int main(int, char**)
|
|||
#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]>,
|
||||
|
|
Loading…
Reference in New Issue