diff --git a/libcxx/include/memory b/libcxx/include/memory --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -2644,6 +2644,34 @@ # define _LIBCPP_SHARED_PTR_TRIVIAL_ABI #endif +template ())> +static true_type __well_formed_delete_op_test(int); + +template +static false_type __well_formed_delete_op_test(...); + +template +struct __well_formed_delete_op : decltype(__well_formed_delete_op_test<_Pt>(0)) {}; + +template ())> +static true_type __well_formed_delete_arr_op_test(int); + +template +static false_type __well_formed_delete_arr_op_test(...); + +template +struct __well_formed_delete_arr_op : decltype(__well_formed_delete_arr_op_test<_Pt>(0)) {}; + +template +struct __shared_ptr_raw_ptr_ctor_reqs +{ + using __delete_op_is_well_formed = typename conditional::value, + __well_formed_delete_arr_op<_Yp*>, + __well_formed_delete_op<_Yp*>>::type; + static const bool value = __compatible_with<_Yp, _Tp>::value && + __delete_op_is_well_formed::value; +}; + template class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr { @@ -2667,7 +2695,7 @@ _LIBCPP_CONSTEXPR shared_ptr(nullptr_t) _NOEXCEPT; template explicit shared_ptr(_Yp* __p, - typename enable_if<__compatible_with<_Yp, element_type>::value, __nat>::type = __nat()); + typename enable_if<__shared_ptr_raw_ptr_ctor_reqs<_Yp, _Tp>::value, __nat>::type = __nat()); template shared_ptr(_Yp* __p, _Dp __d, typename enable_if<__shared_ptr_deleter_ctor_reqs<_Dp, _Yp, element_type>::value, __nat>::type = __nat()); @@ -2925,7 +2953,7 @@ template template shared_ptr<_Tp>::shared_ptr(_Yp* __p, - typename enable_if<__compatible_with<_Yp, element_type>::value, __nat>::type) + typename enable_if<__shared_ptr_raw_ptr_ctor_reqs<_Yp, _Tp>::value, __nat>::type) : __ptr_(__p) { unique_ptr<_Yp> __hold(__p); 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 --- 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 @@ -52,6 +52,28 @@ int C::count = 0; +class private_delete_op +{ + static void operator delete (void *p) { + return delete static_cast(p); + } +public: + static void operator delete[] (void *p) { + return delete[] static_cast(p); + } +}; + +class private_delete_arr_op +{ + static void operator delete[] (void *p) { + return delete[] static_cast(p); + } +public: + static void operator delete (void *p) { + return delete static_cast(p); + } +}; + int main(int, char**) { static_assert(( std::is_convertible, std::shared_ptr >::value), ""); @@ -96,5 +118,19 @@ assert(B::count == 0); assert(A::count == 0); +// This should work in C++03 but we get errors when trying to do SFINAE with the delete operator. +#if TEST_STD_VER >= 11 + { + // Make sure that when T (for std::shared_ptr) is an array type, this constructor only + // participates in overload resolution when `delete[] p` is well formed. And when T is not + // an array type, this constructor only participates in overload resolution when `delete p` + // is well formed. + static_assert(!std::is_constructible, + private_delete_op*>::value, ""); + static_assert(!std::is_constructible, + private_delete_arr_op*>::value, ""); + } +#endif // STD_TEST_VERSION >= 11 + return 0; }