[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:
zoecarver 2021-02-19 11:10:36 -08:00
parent 513463fd26
commit dbc89028d7
5 changed files with 72 additions and 10 deletions

View File

@ -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|",""

1 Issue # Issue Name Meeting Status First released version
300 `2872 <https://wg21.link/LWG2872>`__ Add definition for direct-non-list-initialization Kona |Complete|
301 `2873 <https://wg21.link/LWG2873>`__ Add noexcept to several shared_ptr related functions Kona |Complete|
302 `2874 <https://wg21.link/LWG2874>`__ Constructor ``shared_ptr::shared_ptr(Y*)``\ should be constrained Kona
303 `2875 <https://wg21.link/LWG2875>`__ shared_ptr::shared_ptr(Y\*, D, [|hellip|\ ]) constructors should be constrained Kona |Complete|
304 `2876 <https://wg21.link/LWG2876>`__ ``shared_ptr::shared_ptr(const weak_ptr<Y>&)``\ constructor should be constrained Kona
305 `2878 <https://wg21.link/LWG2878>`__ Missing DefaultConstructible requirement for istream_iterator default constructor Kona |Complete|
306 `2890 <https://wg21.link/LWG2890>`__ The definition of 'object state' applies only to class types Kona |Complete|

View File

@ -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

View File

@ -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;
}

View File

@ -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, "");

View File

@ -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]>,