Index: libcxx/include/concepts =================================================================== --- libcxx/include/concepts +++ libcxx/include/concepts @@ -157,6 +157,12 @@ template<class _Tp, class _Up> concept same_as = __same_as_impl<_Tp, _Up> && __same_as_impl<_Up, _Tp>; +// [concept.derived] + +template<class _Dp, class _Bp> +concept derived_from = + __is_base_of(_Bp, _Dp) && __is_convertible_to(const volatile _Dp*, const volatile _Bp*); + #endif //_LIBCPP_STD_VER > 17 && defined(__cpp_concepts) && __cpp_concepts >= 201811L _LIBCPP_END_NAMESPACE_STD Index: libcxx/test/std/concepts/lang/derived_from.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/concepts/lang/derived_from.pass.cpp @@ -0,0 +1,498 @@ +//===----------------------------------------------------------------------===// +// +// 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<class Derived, class Base> +// concept derived_from; + +#include <concepts> +#include <type_traits> + +struct Base1 {}; +struct Derived1 : Base1 {}; +struct Derived2 : Base1 {}; + +struct DerivedPrivate : private Base1 {}; +struct Derived3 : DerivedPrivate {}; + +struct DerivedProtected : protected DerivedPrivate {}; +struct Derived4 : DerivedProtected {}; +struct Derived5 : Derived4 {}; + +template <typename From, typename To> +constexpr void CheckNotDerivedFromPointer() { + { // From as pointer + static_assert(!std::derived_from<From*, To>); + static_assert(!std::derived_from<From*, const To>); + static_assert(!std::derived_from<From*, volatile To>); + static_assert(!std::derived_from<From*, const volatile To>); + + if constexpr (!std::same_as<To, void>) { + static_assert(!std::derived_from<From*, To&>); + static_assert(!std::derived_from<From*, const To&>); + static_assert(!std::derived_from<From*, volatile To&>); + static_assert(!std::derived_from<From*, const volatile To&>); + + static_assert(!std::derived_from<From*, To&&>); + static_assert(!std::derived_from<From*, const To&&>); + static_assert(!std::derived_from<From*, volatile To&&>); + static_assert(!std::derived_from<From*, const volatile To&&>); + + static_assert(!std::derived_from<const From*, To&>); + static_assert(!std::derived_from<const From*, const To&>); + static_assert(!std::derived_from<const From*, volatile To&>); + static_assert(!std::derived_from<const From*, const volatile To&>); + + static_assert(!std::derived_from<const From*, To&&>); + static_assert(!std::derived_from<const From*, const To&&>); + static_assert(!std::derived_from<const From*, volatile To&&>); + static_assert(!std::derived_from<const From*, const volatile To&&>); + + static_assert(!std::derived_from<volatile From*, To&>); + static_assert(!std::derived_from<volatile From*, const To&>); + static_assert(!std::derived_from<volatile From*, volatile To&>); + static_assert(!std::derived_from<volatile From*, const volatile To&>); + + static_assert(!std::derived_from<volatile From*, To&&>); + static_assert(!std::derived_from<volatile From*, const To&&>); + static_assert(!std::derived_from<volatile From*, volatile To&&>); + static_assert(!std::derived_from<volatile From*, const volatile To&&>); + + static_assert(!std::derived_from<const volatile From*, To&>); + static_assert(!std::derived_from<const volatile From*, const To&>); + static_assert(!std::derived_from<const volatile From*, volatile To&>); + static_assert( + !std::derived_from<const volatile From*, const volatile To&>); + + static_assert(!std::derived_from<const volatile From*, To&&>); + static_assert(!std::derived_from<const volatile From*, const To&&>); + static_assert(!std::derived_from<const volatile From*, volatile To&&>); + static_assert( + !std::derived_from<const volatile From*, const volatile To&&>); + } + } + { // To as pointer + static_assert(!std::derived_from<From, To*>); + static_assert(!std::derived_from<From, const To*>); + static_assert(!std::derived_from<From, volatile To*>); + static_assert(!std::derived_from<From, const volatile To*>); + + if constexpr (!std::same_as<From, void>) { + static_assert(!std::derived_from<From&, To*>); + static_assert(!std::derived_from<From&, const To*>); + static_assert(!std::derived_from<From&, volatile To*>); + static_assert(!std::derived_from<From&, const volatile To*>); + + static_assert(!std::derived_from<From&&, To*>); + static_assert(!std::derived_from<From&&, const To*>); + static_assert(!std::derived_from<From&&, volatile To*>); + static_assert(!std::derived_from<From&&, const volatile To*>); + + static_assert(!std::derived_from<const From&, To*>); + static_assert(!std::derived_from<const From&, const To*>); + static_assert(!std::derived_from<const From&, volatile To*>); + static_assert(!std::derived_from<const From&, const volatile To*>); + + static_assert(!std::derived_from<const From&&, To*>); + static_assert(!std::derived_from<const From&&, const To*>); + static_assert(!std::derived_from<const From&&, volatile To*>); + static_assert(!std::derived_from<const From&&, const volatile To*>); + + static_assert(!std::derived_from<volatile From&, To*>); + static_assert(!std::derived_from<volatile From&, const To*>); + static_assert(!std::derived_from<volatile From&, volatile To*>); + static_assert(!std::derived_from<volatile From&, const volatile To*>); + + static_assert(!std::derived_from<volatile From&&, To*>); + static_assert(!std::derived_from<volatile From&&, const To*>); + static_assert(!std::derived_from<volatile From&&, volatile To*>); + static_assert(!std::derived_from<volatile From&&, const volatile To*>); + + static_assert(!std::derived_from<const volatile From&, To*>); + static_assert(!std::derived_from<const volatile From&, const To*>); + static_assert(!std::derived_from<const volatile From&, volatile To*>); + static_assert( + !std::derived_from<const volatile From&, const volatile To*>); + + static_assert(!std::derived_from<const volatile From&&, To*>); + static_assert(!std::derived_from<const volatile From&&, const To*>); + static_assert(!std::derived_from<const volatile From&&, volatile To*>); + static_assert( + !std::derived_from<const volatile From&&, const volatile To*>); + } + } + { // Both as pointers + static_assert(!std::derived_from<From*, To*>); + static_assert(!std::derived_from<From*, const To*>); + static_assert(!std::derived_from<From*, volatile To*>); + static_assert(!std::derived_from<From*, const volatile To*>); + + static_assert(!std::derived_from<const From*, To*>); + static_assert(!std::derived_from<const From*, const To*>); + static_assert(!std::derived_from<const From*, volatile To*>); + static_assert(!std::derived_from<const From*, const volatile To*>); + + static_assert(!std::derived_from<volatile From*, To*>); + static_assert(!std::derived_from<volatile From*, const To*>); + static_assert(!std::derived_from<volatile From*, volatile To*>); + static_assert(!std::derived_from<volatile From*, const volatile To*>); + + static_assert(!std::derived_from<const volatile From*, To*>); + static_assert(!std::derived_from<const volatile From*, const To*>); + static_assert(!std::derived_from<const volatile From*, volatile To*>); + static_assert(!std::derived_from<const volatile From*, const volatile To*>); + } + + // From as the return type of a pointer-to-function + if constexpr (!std::is_array_v<From>) { + static_assert(!std::derived_from<From (*)(), To>); + static_assert(!std::derived_from<From (*)(int), To>); + } + + // To as the return type of a pointer-to-function + if constexpr (!std::is_array_v<To>) { + static_assert(!std::derived_from<From, To (*)()>); + static_assert(!std::derived_from<From, To (*)(double)>); + } + + // Both as the return type of a pointer-to-function + if constexpr (!std::is_array_v<From> && !std::is_array_v<To>) { + static_assert(!std::derived_from<From (*)(), To (*)()>); + static_assert(!std::derived_from<From (*)(int), To (*)(double)>); + } + { // pointer-to-member + if constexpr (std::is_class_v<From> && !std::same_as<To, void>) { + static_assert(!std::derived_from<To From::*, To>); + } + + if constexpr (std::is_class_v<To> && !std::same_as<From, void>) { + static_assert(!std::derived_from<From To::*, From>); + } + } + { // pointer-to-member-functions + if constexpr (std::is_class_v<From>) { + static_assert(!std::derived_from<From (From::*)(), To>); + } + + if constexpr (std::is_class_v<To>) { + static_assert(!std::derived_from<To (To::*)(), From>); + } + } +} + +template <typename From, typename To> +constexpr void CheckNotDerivedFromReference() { + if constexpr (!std::same_as<To, void>) { + static_assert(!std::derived_from<From, To&>); + static_assert(!std::derived_from<From, const To&>); + static_assert(!std::derived_from<From, volatile To&>); + static_assert(!std::derived_from<From, const volatile To&>); + + static_assert(!std::derived_from<From, To&&>); + static_assert(!std::derived_from<From, const To&&>); + static_assert(!std::derived_from<From, volatile To&&>); + static_assert(!std::derived_from<From, const volatile To&&>); + } + + if constexpr (!std::same_as<From, void>) { + static_assert(!std::derived_from<From&, To>); + static_assert(!std::derived_from<From&, To>); + static_assert(!std::derived_from<From&, To>); + static_assert(!std::derived_from<From&, To>); + + static_assert(!std::derived_from<From&&, To>); + static_assert(!std::derived_from<From&&, To>); + static_assert(!std::derived_from<From&&, To>); + static_assert(!std::derived_from<From&&, To>); + } + + // From as lvalue references + if constexpr (!std::same_as<From, void> && !std::same_as<To, void>) { + static_assert(!std::derived_from<From&, To&>); + static_assert(!std::derived_from<From&, const To&>); + static_assert(!std::derived_from<From&, volatile To&>); + static_assert(!std::derived_from<From&, const volatile To&>); + + static_assert(!std::derived_from<From&, To&&>); + static_assert(!std::derived_from<From&, const To&&>); + static_assert(!std::derived_from<From&, volatile To&&>); + static_assert(!std::derived_from<From&, const volatile To&&>); + + static_assert(!std::derived_from<const From&, To&>); + static_assert(!std::derived_from<const From&, const To&>); + static_assert(!std::derived_from<const From&, volatile To&>); + static_assert(!std::derived_from<const From&, const volatile To&>); + + static_assert(!std::derived_from<const From&, To&&>); + static_assert(!std::derived_from<const From&, const To&&>); + static_assert(!std::derived_from<const From&, volatile To&&>); + static_assert(!std::derived_from<const From&, const volatile To&&>); + + static_assert(!std::derived_from<volatile From&, To&>); + static_assert(!std::derived_from<volatile From&, const To&>); + static_assert(!std::derived_from<volatile From&, volatile To&>); + static_assert(!std::derived_from<volatile From&, const volatile To&>); + + static_assert(!std::derived_from<volatile From&, To&&>); + static_assert(!std::derived_from<volatile From&, const To&&>); + static_assert(!std::derived_from<volatile From&, volatile To&&>); + static_assert(!std::derived_from<volatile From&, const volatile To&&>); + + static_assert(!std::derived_from<const volatile From&, To&>); + static_assert(!std::derived_from<const volatile From&, const To&>); + static_assert(!std::derived_from<const volatile From&, volatile To&>); + static_assert(!std::derived_from<const volatile From&, const volatile To&>); + + static_assert(!std::derived_from<const volatile From&, To&&>); + static_assert(!std::derived_from<const volatile From&, const To&&>); + static_assert(!std::derived_from<const volatile From&, volatile To&&>); + static_assert( + !std::derived_from<const volatile From&, const volatile To&&>); + + // From as rvalue references + static_assert(!std::derived_from<From&&, To&>); + static_assert(!std::derived_from<From&&, const To&>); + static_assert(!std::derived_from<From&&, volatile To&>); + static_assert(!std::derived_from<From&&, const volatile To&>); + + static_assert(!std::derived_from<From&&, To&&>); + static_assert(!std::derived_from<From&&, const To&&>); + static_assert(!std::derived_from<From&&, volatile To&&>); + static_assert(!std::derived_from<From&&, const volatile To&&>); + + static_assert(!std::derived_from<const From&&, To&>); + static_assert(!std::derived_from<const From&&, const To&>); + static_assert(!std::derived_from<const From&&, volatile To&>); + static_assert(!std::derived_from<const From&&, const volatile To&>); + + static_assert(!std::derived_from<const From&&, To&&>); + static_assert(!std::derived_from<const From&&, const To&&>); + static_assert(!std::derived_from<const From&&, volatile To&&>); + static_assert(!std::derived_from<const From&&, const volatile To&&>); + + static_assert(!std::derived_from<volatile From&&, To&>); + static_assert(!std::derived_from<volatile From&&, const To&>); + static_assert(!std::derived_from<volatile From&&, volatile To&>); + static_assert(!std::derived_from<volatile From&&, const volatile To&>); + + static_assert(!std::derived_from<volatile From&&, To&&>); + static_assert(!std::derived_from<volatile From&&, const To&&>); + static_assert(!std::derived_from<volatile From&&, volatile To&&>); + static_assert(!std::derived_from<volatile From&&, const volatile To&&>); + + static_assert(!std::derived_from<const volatile From&&, To&>); + static_assert(!std::derived_from<const volatile From&&, const To&>); + static_assert(!std::derived_from<const volatile From&&, volatile To&>); + static_assert( + !std::derived_from<const volatile From&&, const volatile To&>); + + static_assert(!std::derived_from<const volatile From&&, To&&>); + static_assert(!std::derived_from<const volatile From&&, const To&&>); + static_assert(!std::derived_from<const volatile From&&, volatile To&&>); + static_assert( + !std::derived_from<const volatile From&&, const volatile To&&>); + } + + // From as the return type of a reference-to-function + if constexpr (!std::is_array_v<From>) { + static_assert(!std::derived_from<From (&)(), To>); + static_assert(!std::derived_from<From (&)(int), To>); + } + // To as the return type of a reference-to-function + if constexpr (!std::is_array_v<To>) { + static_assert(!std::derived_from<From, To (&)()>); + static_assert(!std::derived_from<From, To (&)(double)>); + } + // Both as the return type of a reference-to-function + if constexpr (!std::is_array_v<From> && !std::is_array_v<To>) { + static_assert(!std::derived_from<From (&)(), To (&)()>); + static_assert(!std::derived_from<From (&)(int), To (&)(double)>); + } +} + +template <typename From, typename To> +constexpr void CheckDerivedFrom() { + static_assert(std::derived_from<From, To>); + + static_assert(std::derived_from<From, const To>); + static_assert(std::derived_from<From, volatile To>); + static_assert(std::derived_from<From, const volatile To>); + + static_assert(std::derived_from<const From, const To>); + static_assert(std::derived_from<const From, volatile To>); + static_assert(std::derived_from<const From, const volatile To>); + + static_assert(std::derived_from<volatile From, const To>); + static_assert(std::derived_from<volatile From, volatile To>); + static_assert(std::derived_from<volatile From, const volatile To>); + + static_assert(std::derived_from<const volatile From, const To>); + static_assert(std::derived_from<const volatile From, volatile To>); + static_assert(std::derived_from<const volatile From, const volatile To>); + + CheckNotDerivedFromPointer<From, To>(); + CheckNotDerivedFromReference<From, To>(); +} + +template <typename From, typename To> +constexpr void CheckNotDerivedFrom() { + static_assert(!std::derived_from<From, To>); + + static_assert(!std::derived_from<From, const To>); + static_assert(!std::derived_from<From, volatile To>); + static_assert(!std::derived_from<From, const volatile To>); + + static_assert(!std::derived_from<const From, const To>); + static_assert(!std::derived_from<const From, volatile To>); + static_assert(!std::derived_from<const From, const volatile To>); + + static_assert(!std::derived_from<volatile From, const To>); + static_assert(!std::derived_from<volatile From, volatile To>); + static_assert(!std::derived_from<volatile From, const volatile To>); + + static_assert(!std::derived_from<const volatile From, const To>); + static_assert(!std::derived_from<const volatile From, volatile To>); + static_assert(!std::derived_from<const volatile From, const volatile To>); + + CheckNotDerivedFromPointer<From, To>(); + CheckNotDerivedFromReference<From, To>(); +} + +enum Enumeration { Yes, No }; +enum class ScopedEnumeration : int { No, Yes }; + +int main(int, char**) { + { // Fundamentals shouldn't be derived from anything + CheckNotDerivedFrom<int, long>(); + CheckNotDerivedFrom<signed char, char>(); + CheckNotDerivedFrom<double, Base1>(); + + CheckNotDerivedFrom<int, Enumeration>(); + CheckNotDerivedFrom<int, ScopedEnumeration>(); + + CheckNotDerivedFrom<void, void>(); + CheckNotDerivedFrom<int, int>(); + } + { // Nothing should be derived from a fundamental type + CheckNotDerivedFrom<Enumeration, int>(); + CheckNotDerivedFrom<ScopedEnumeration, int>(); + + CheckNotDerivedFrom<Base1, int>(); + CheckNotDerivedFrom<Base1, double>(); + CheckNotDerivedFrom<Derived1, char>(); + CheckNotDerivedFrom<DerivedPrivate, long long>(); + } + { // Other built-in things shouldn't have derivations + CheckNotDerivedFrom<Enumeration, Enumeration>(); + CheckNotDerivedFrom<ScopedEnumeration, ScopedEnumeration>(); + + CheckNotDerivedFrom<Enumeration, ScopedEnumeration>(); + CheckNotDerivedFrom<ScopedEnumeration, Enumeration>(); + + CheckNotDerivedFrom<Base1[5], Base1>(); + CheckNotDerivedFrom<Derived1[5], Base1>(); + + CheckNotDerivedFrom<Base1, Base1[5]>(); + CheckNotDerivedFrom<Derived1, Base1[5]>(); + } + + { // Base1 is the subject. + CheckDerivedFrom<Base1, Base1>(); + + CheckNotDerivedFrom<Base1, void>(); + CheckNotDerivedFrom<Base1, DerivedPrivate>(); + CheckNotDerivedFrom<Base1, DerivedProtected>(); + CheckNotDerivedFrom<Base1, Derived1>(); + CheckNotDerivedFrom<Base1, Derived2>(); + CheckNotDerivedFrom<Base1, Derived3>(); + CheckNotDerivedFrom<Base1, Derived4>(); + } + + { // Derived1 is the subject. + CheckDerivedFrom<Derived1, Base1>(); + CheckDerivedFrom<Derived1, Derived1>(); + + CheckNotDerivedFromPointer<Derived1, void>(); + CheckNotDerivedFrom<Derived1, DerivedPrivate>(); + CheckNotDerivedFrom<Derived1, DerivedProtected>(); + CheckNotDerivedFrom<Derived1, Derived2>(); + CheckNotDerivedFrom<Derived1, Derived3>(); + CheckNotDerivedFrom<Derived1, Derived4>(); + } + + { // Derived2 is the subject. + CheckDerivedFrom<Derived2, Base1>(); + CheckDerivedFrom<Derived2, Derived2>(); + + CheckNotDerivedFrom<Derived2, DerivedPrivate>(); + CheckNotDerivedFrom<Derived2, DerivedProtected>(); + CheckNotDerivedFrom<Derived2, Derived1>(); + CheckNotDerivedFrom<Derived2, Derived3>(); + CheckNotDerivedFrom<Derived2, Derived4>(); + } + + { // DerivedPrivate is the subject. + CheckDerivedFrom<DerivedPrivate, DerivedPrivate>(); + + CheckNotDerivedFrom<DerivedPrivate, Base1>(); + CheckNotDerivedFrom<DerivedPrivate, DerivedProtected>(); + CheckNotDerivedFrom<DerivedPrivate, Derived1>(); + CheckNotDerivedFrom<DerivedPrivate, Derived2>(); + CheckNotDerivedFrom<DerivedPrivate, Derived3>(); + CheckNotDerivedFrom<DerivedPrivate, Derived4>(); + } + + { // Derived3 is the subject. + CheckDerivedFrom<Derived3, DerivedPrivate>(); + CheckDerivedFrom<Derived3, Derived3>(); + + CheckNotDerivedFrom<Derived3, Base1>(); + CheckNotDerivedFrom<Derived3, DerivedProtected>(); + CheckNotDerivedFrom<Derived3, Derived1>(); + CheckNotDerivedFrom<Derived3, Derived2>(); + CheckNotDerivedFrom<Derived3, Derived4>(); + } + + { // DerivedProtected is the subject. + CheckDerivedFrom<DerivedProtected, DerivedProtected>(); + + CheckNotDerivedFromPointer<DerivedProtected, Base1>(); + CheckNotDerivedFromPointer<DerivedProtected, DerivedPrivate>(); + CheckNotDerivedFromPointer<DerivedProtected, Derived1>(); + CheckNotDerivedFromPointer<DerivedProtected, Derived2>(); + CheckNotDerivedFromPointer<DerivedProtected, Derived3>(); + CheckNotDerivedFromPointer<DerivedProtected, Derived4>(); + } + + { // Derived4 is the subject. + CheckDerivedFrom<Derived4, DerivedProtected>(); + CheckDerivedFrom<Derived4, Derived4>(); + + CheckNotDerivedFrom<Derived4, Base1>(); + CheckNotDerivedFrom<Derived4, DerivedPrivate>(); + CheckNotDerivedFrom<Derived4, Derived1>(); + CheckNotDerivedFrom<Derived4, Derived2>(); + CheckNotDerivedFrom<Derived4, Derived3>(); + } + + { // Derived5 is the subject. + CheckDerivedFrom<Derived5, DerivedProtected>(); + CheckDerivedFrom<Derived5, Derived4>(); + CheckDerivedFrom<Derived5, Derived5>(); + + CheckNotDerivedFrom<Derived5, Base1>(); + CheckNotDerivedFrom<Derived5, DerivedPrivate>(); + CheckNotDerivedFrom<Derived5, Derived1>(); + CheckNotDerivedFrom<Derived5, Derived2>(); + CheckNotDerivedFrom<Derived5, Derived3>(); + } + + return 0; +}