diff --git a/libcxx/include/memory b/libcxx/include/memory --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -3537,6 +3537,41 @@ : is_convertible<_Tp*, _Up*> {}; #endif // _LIBCPP_STD_VER > 14 +#ifndef _LIBCPP_CXX03_LANG +// In C++03 we get errors when trying to do SFINAE with the delete operator. +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 +{ + static const bool value = __compatible_with<_Yp, _Tp>::value && + ((is_array<_Tp>::value && __well_formed_delete_arr_op<_Yp*>::value) || + (!is_array<_Tp>::value && __well_formed_delete_op<_Yp*>::value)); +}; + +#else // if defined _LIBCPP_CXX03_LANG + +template +struct __shared_ptr_raw_ptr_ctor_reqs : __compatible_with<_Tp, _Yp> { }; + +#endif // not defined _LIBCPP_CXX03_LANG + template class _LIBCPP_TEMPLATE_VIS shared_ptr { @@ -3560,7 +3595,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<__compatible_with<_Yp, element_type>::value, __nat>::type = __nat()); @@ -3845,7 +3880,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 STD_TEST_VERSION >= 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; }