Index: libcxx/include/concepts =================================================================== --- libcxx/include/concepts +++ libcxx/include/concepts @@ -163,6 +163,17 @@ concept derived_from = __is_base_of(_Bp, _Dp) && __is_convertible_to(const volatile _Dp*, const volatile _Bp*); +// [concept.convertible] + +template +inline constexpr auto __is_explicitly_convertible = + requires(add_rvalue_reference_t<_Fp> (&__f)()) { + static_cast<_Tp>(__f()); + }; + +template +concept convertible_to = __is_convertible_to(_Fp, _Tp) && __is_explicitly_convertible<_Fp, _Tp>; + #endif //_LIBCPP_STD_VER > 17 && defined(__cpp_concepts) && __cpp_concepts >= 201811L _LIBCPP_END_NAMESPACE_STD Index: libcxx/test/std/concepts/lang/convertible_to.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/concepts/lang/convertible_to.pass.cpp @@ -0,0 +1,507 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts + +// template +// concept convertible_to; + +#include +#include + +template class Mod1, + template class Mod2> +constexpr void NotConvertible() { + static_assert( + !std::convertible_to::type, typename Mod2::type>); + static_assert( + !std::convertible_to::type, typename Mod1::type>); +} + +template class Mod1, + template class Mod2> +constexpr void OneWayConvertible() { + static_assert( + std::convertible_to::type, typename Mod2::type>); + static_assert( + !std::convertible_to::type, typename Mod1::type>); +} + +template class Mod1, + template class Mod2> +constexpr void TwoWayConvertible() { + static_assert( + std::convertible_to::type, typename Mod2::type>); + static_assert( + std::convertible_to::type, typename Mod1::type>); +} + +struct S {}; +enum Enumeration { No, Yes }; +enum class ScopedEnumeration { Yes, No }; +template +struct Identity { + using type = T; +}; + +// Tests that should objectively return false +template class Mod1, template class Mod2, + class TT = std::remove_cvref_t > +requires (!std::is_array_v && !std::is_void_v && // + !std::is_pointer_v && !std::is_function_v && // + !std::is_member_pointer_v) // +constexpr void CommonlyNotConvertible() { + NotConvertible(); + NotConvertible::type*, Mod1, Identity>(); + NotConvertible::type S::*, Mod1, Identity>(); + NotConvertible::type (S::*)(), Mod1, Identity>(); + NotConvertible::type[sizeof(T)], Mod1, Identity>(); + NotConvertible::type (*)(), Mod1, Identity>(); + NotConvertible::type (&)(), Mod1, Identity>(); +} + +template