diff --git a/libcxx/include/concepts b/libcxx/include/concepts --- a/libcxx/include/concepts +++ b/libcxx/include/concepts @@ -157,6 +157,15 @@ template concept same_as = __same_as_impl<_Tp, _Up> && __same_as_impl<_Up, _Tp>; +// [concept.convertible] + +template +concept convertible_to = + __is_convertible_to(_From, _To) && + requires(add_rvalue_reference_t<_From> (&__f)()) { + static_cast<_To>(__f()); + }; + // [concept.destructible] template @@ -176,7 +185,6 @@ concept default_initializable = constructible_from<_Tp> && requires { _Tp{}; } && __default_initializable<_Tp>; - #endif //_LIBCPP_STD_VER > 17 && defined(__cpp_concepts) && __cpp_concepts >= 201811L _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/std/concepts/lang/convertible_to.pass.cpp b/libcxx/test/std/concepts/lang/convertible_to.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/concepts/lang/convertible_to.pass.cpp @@ -0,0 +1,422 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +namespace { +enum ClassicEnum { a, b }; +enum class ScopedEnum { x, y }; +struct Empty {}; +using nullptr_t = decltype(nullptr); + +template +void CheckConvertibleTo() { + static_assert(std::convertible_to); + static_assert(std::convertible_to); + static_assert(std::convertible_to); + static_assert(std::convertible_to); +} + +template +void CheckNotConvertibleTo() { + static_assert(!std::convertible_to); + static_assert(!std::convertible_to); + static_assert(!std::convertible_to); + static_assert(!std::convertible_to); +} + +template +void CheckIsConvertibleButNotConvertibleTo() { + // Sanity check T is either implicitly xor explicitly convertible to U. + static_assert(std::is_convertible_v); + static_assert(std::is_convertible_v); + static_assert(std::is_convertible_v); + static_assert(std::is_convertible_v); + CheckNotConvertibleTo(); +} + +// Tests that should objectively return false (except for bool and nullptr_t) +template +constexpr void CommonlyNotConvertibleTo() { + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); +} + +template > +constexpr void CommonlyNotConvertibleTo() { + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckConvertibleTo(); + CheckConvertibleTo(); + CheckConvertibleTo(); + CheckConvertibleTo(); + CheckConvertibleTo(); + CheckConvertibleTo(); +} + +template > +constexpr void CommonlyNotConvertibleTo() { + CheckNotConvertibleTo(); + CheckConvertibleTo(); + CheckConvertibleTo(); + CheckConvertibleTo(); + CheckConvertibleTo(); + CheckNotConvertibleTo(); + CheckConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); +} +} // namespace + +using Function = void(); +using NoexceptFunction = void() noexcept; +using ConstFunction = void() const; +using Array = char[1]; + +struct StringType { + StringType(const char*) {} +}; + +class NonCopyable { + NonCopyable(NonCopyable&); +}; + +template +class CannotInstantiate { + enum { X = T::ThisExpressionWillBlowUp }; +}; + +struct abstract { + virtual int f() = 0; +}; + +struct ExplicitlyConvertible; +struct ImplicitlyConvertible; + +struct ExplicitlyConstructible { + explicit ExplicitlyConstructible(int); + explicit ExplicitlyConstructible(ExplicitlyConvertible); + explicit ExplicitlyConstructible(ImplicitlyConvertible) = delete; +}; + +struct ExplicitlyConvertible { + explicit operator ExplicitlyConstructible() const { + return ExplicitlyConstructible(0); + } +}; + +struct ImplicitlyConstructible; + +struct ImplicitlyConvertible { + operator ExplicitlyConstructible() const; + operator ImplicitlyConstructible() const = delete; +}; + +struct ImplicitlyConstructible { + ImplicitlyConstructible(ImplicitlyConvertible); +}; + +int main(int, char**) { + // void + CheckConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + + // Function + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckConvertibleTo(); + CheckConvertibleTo(); + CheckConvertibleTo(); + + static_assert(std::convertible_to); + static_assert(!std::convertible_to); + + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + + // Function& + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckConvertibleTo(); + + CheckConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + + // Function* + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckConvertibleTo(); + + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + + // Non-referencable function type + static_assert(!std::convertible_to); + static_assert(!std::convertible_to); + static_assert(!std::convertible_to); + static_assert(!std::convertible_to); + static_assert(!std::convertible_to); + static_assert(!std::convertible_to); + static_assert(!std::convertible_to); + static_assert(!std::convertible_to); + + // NoexceptFunction + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckConvertibleTo(); + CheckConvertibleTo(); + CheckConvertibleTo(); + CheckConvertibleTo(); + CheckConvertibleTo(); + CheckConvertibleTo(); + + static_assert(std::convertible_to); + static_assert(std::convertible_to); + + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + + // NoexceptFunction& + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckConvertibleTo(); + CheckConvertibleTo(); + + CheckConvertibleTo(); + CheckConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + + // NoexceptFunction* + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckConvertibleTo(); + CheckConvertibleTo(); + + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + + // Array + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + + static_assert(!std::convertible_to); + static_assert(std::convertible_to); + static_assert(!std::convertible_to); + + static_assert(!std::convertible_to); + static_assert(std::convertible_to); + static_assert(!std::convertible_to); + static_assert(!std::convertible_to); + + static_assert(std::convertible_to); + static_assert(std::convertible_to); + static_assert(std::convertible_to); + static_assert(std::convertible_to); + static_assert(std::convertible_to); + static_assert(!std::convertible_to); + static_assert(!std::convertible_to); + + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + + static_assert(std::convertible_to); + static_assert(std::convertible_to); + static_assert(std::convertible_to); + static_assert(std::convertible_to); + + static_assert(!std::convertible_to); + static_assert(std::convertible_to); + + static_assert(!std::convertible_to); + static_assert(!std::convertible_to); + + // Array& + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + + static_assert(std::convertible_to); + static_assert(std::convertible_to); + static_assert(!std::convertible_to); + static_assert(std::convertible_to); + + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + + static_assert(std::convertible_to); + static_assert(std::convertible_to); + static_assert(!std::convertible_to); + static_assert(std::convertible_to); + + static_assert(std::convertible_to); + static_assert(std::convertible_to); + + // char + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + + CheckConvertibleTo(); + + static_assert(!std::convertible_to); + static_assert(std::convertible_to); + static_assert(!std::convertible_to); + static_assert(std::convertible_to); + + CheckNotConvertibleTo(); + + // char& + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + + CheckConvertibleTo(); + + static_assert(std::convertible_to); + static_assert(std::convertible_to); + static_assert(!std::convertible_to); + static_assert(std::convertible_to); + + CheckNotConvertibleTo(); + + // char* + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + + static_assert(std::convertible_to); + static_assert(std::convertible_to); + static_assert(!std::convertible_to); + static_assert(std::convertible_to); + + // NonCopyable + static_assert(std::convertible_to); + static_assert(std::convertible_to); + static_assert(std::convertible_to); + static_assert(std::convertible_to); + static_assert(std::convertible_to); + static_assert( + std::convertible_to); + static_assert( + std::convertible_to); + static_assert(std::convertible_to); + static_assert(!std::convertible_to); + + // This test requires Access control SFINAE which we only have in C++11 or when + // we are using the compiler builtin for convertible_to. + CheckNotConvertibleTo(); + + // Ensure that CannotInstantiate is not instantiated by convertible_to when it is not needed. + // For example CannotInstantiate is instantiated as a part of ADL lookup for arguments of type CannotInstantiate*. + static_assert( + std::convertible_to*, CannotInstantiate*>); + + // Test for PR13592 + static_assert(!std::convertible_to); + + CommonlyNotConvertibleTo(); + CommonlyNotConvertibleTo(); + CommonlyNotConvertibleTo(); + + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckNotConvertibleTo(); + CheckIsConvertibleButNotConvertibleTo(); + CheckNotConvertibleTo(); + + return 0; +}