Skip to content

[libc++] Implement P2985R0: std::is_virtual_base_of #105847

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libcxx/docs/FeatureTestMacroTable.rst
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_inplace_vector`` *unimplemented*
---------------------------------------------------------- -----------------
``__cpp_lib_is_virtual_base_of`` *unimplemented*
``__cpp_lib_is_virtual_base_of`` ``202406L``
---------------------------------------------------------- -----------------
``__cpp_lib_is_within_lifetime`` *unimplemented*
---------------------------------------------------------- -----------------
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/ReleaseNotes/20.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ What's New in Libc++ 20.0.0?
Implemented Papers
------------------

- TODO
- P2985R0: A type trait for detecting virtual base classes (`Github <https://github.com/llvm/llvm-project/issues/105432>`__)


Improvements and New Features
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx2cPapers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
"`P2389R2 <https://wg21.link/P2389R2>`__","``dextents`` Index Type Parameter","2024-06 (St. Louis)","|Complete|","19.0",""
"`P3168R2 <https://wg21.link/P3168R2>`__","Give ``std::optional`` Range Support","2024-06 (St. Louis)","","","|ranges|"
"`P3217R0 <https://wg21.link/P3217R0>`__","Adjoints to 'Enabling list-initialization for algorithms': find_last","2024-06 (St. Louis)","","",""
"`P2985R0 <https://wg21.link/P2985R0>`__","A type trait for detecting virtual base classes","2024-06 (St. Louis)","","",""
"`P2985R0 <https://wg21.link/P2985R0>`__","A type trait for detecting virtual base classes","2024-06 (St. Louis)","|Complete|","20.0",""
"`P0843R14 <https://wg21.link/P0843R14>`__","``inplace_vector``","2024-06 (St. Louis)","","",""
"`P3235R3 <https://wg21.link/P3235R3>`__","``std::print`` more types faster with less memory","2024-06 (St. Louis)","","","|format| |DR|"
"`P2968R2 <https://wg21.link/P2968R2>`__","Make ``std::ignore`` a first-class object","2024-06 (St. Louis)","|Complete|","19.0",""
Expand Down
12 changes: 12 additions & 0 deletions libcxx/include/__type_traits/is_base_of.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@ template <class _Bp, class _Dp>
inline constexpr bool is_base_of_v = __is_base_of(_Bp, _Dp);
#endif

#if _LIBCPP_STD_VER >= 26
# if __has_builtin(__builtin_is_virtual_base_of)

template <class _Base, class _Derived>
struct _LIBCPP_TEMPLATE_VIS is_virtual_base_of : public bool_constant<__builtin_is_virtual_base_of(_Base, _Derived)> {};

template <class _Base, class _Derived>
inline constexpr bool is_virtual_base_of_v = __builtin_is_virtual_base_of(_Base, _Derived);

# endif
#endif

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___TYPE_TRAITS_IS_BASE_OF_H
3 changes: 3 additions & 0 deletions libcxx/include/type_traits
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ namespace std
// Relationships between types:
template <class T, class U> struct is_same;
template <class Base, class Derived> struct is_base_of;
template <class Base, class Derived> struct is_virtual_base_of; // C++26

template <class From, class To> struct is_convertible;
template <typename From, typename To> struct is_nothrow_convertible; // C++20
Expand Down Expand Up @@ -391,6 +392,8 @@ namespace std
= is_same<T, U>::value; // C++17
template <class Base, class Derived> inline constexpr bool is_base_of_v
= is_base_of<Base, Derived>::value; // C++17
template <class Base, class Derived> inline constexpr bool is_virtual_base_of_v
= is_virtual_base_of<Base, Derived>::value; // C++26
template <class From, class To> inline constexpr bool is_convertible_v
= is_convertible<From, To>::value; // C++17
template <class Fn, class... ArgTypes> inline constexpr bool is_invocable_v
Expand Down
4 changes: 3 additions & 1 deletion libcxx/include/version
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,9 @@ __cpp_lib_void_t 201411L <type_traits>
// # define __cpp_lib_generate_random 202403L
// # define __cpp_lib_hazard_pointer 202306L
// # define __cpp_lib_inplace_vector 202406L
// # define __cpp_lib_is_virtual_base_of 202406L
# if __has_builtin(__builtin_is_virtual_base_of)
# define __cpp_lib_is_virtual_base_of 202406L
# endif
// # define __cpp_lib_is_within_lifetime 202306L
// # define __cpp_lib_linalg 202311L
# undef __cpp_lib_mdspan
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -857,16 +857,16 @@
# error "__cpp_lib_is_swappable should have the value 201603L in c++26"
# endif

# if !defined(_LIBCPP_VERSION)
# if __has_builtin(__builtin_is_virtual_base_of)
# ifndef __cpp_lib_is_virtual_base_of
# error "__cpp_lib_is_virtual_base_of should be defined in c++26"
# endif
# if __cpp_lib_is_virtual_base_of != 202406L
# error "__cpp_lib_is_virtual_base_of should have the value 202406L in c++26"
# endif
# else // _LIBCPP_VERSION
# else
# ifdef __cpp_lib_is_virtual_base_of
# error "__cpp_lib_is_virtual_base_of should not be defined because it is unimplemented in libc++!"
# error "__cpp_lib_is_virtual_base_of should not be defined when the requirement '__has_builtin(__builtin_is_virtual_base_of)' is not met!"
# endif
# endif

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7172,16 +7172,16 @@
# error "__cpp_lib_is_swappable should have the value 201603L in c++26"
# endif

# if !defined(_LIBCPP_VERSION)
# if __has_builtin(__builtin_is_virtual_base_of)
# ifndef __cpp_lib_is_virtual_base_of
# error "__cpp_lib_is_virtual_base_of should be defined in c++26"
# endif
# if __cpp_lib_is_virtual_base_of != 202406L
# error "__cpp_lib_is_virtual_base_of should have the value 202406L in c++26"
# endif
# else // _LIBCPP_VERSION
# else
# ifdef __cpp_lib_is_virtual_base_of
# error "__cpp_lib_is_virtual_base_of should not be defined because it is unimplemented in libc++!"
# error "__cpp_lib_is_virtual_base_of should not be defined when the requirement '__has_builtin(__builtin_is_virtual_base_of)' is not met!"
# endif
# endif

Expand Down
166 changes: 166 additions & 0 deletions libcxx/test/std/utilities/meta/meta.rel/is_virtual_base_of.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
//===----------------------------------------------------------------------===//
//
// 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++03, c++11, c++14, c++17, c++20, c++23

// These compilers don't support __builtin_is_virtual_base_of yet.
// UNSUPPORTED: clang-17, clang-18, clang-19, gcc-14, apple-clang-16, apple-clang-17

// <type_traits>

// std::is_virtual_base_of

#include <type_traits>
#include <cassert>

template <bool expected, class Base, class Derived>
void test() {
// Test the type of the variables
{
static_assert(std::is_same_v<bool const, decltype(std::is_virtual_base_of<Base, Derived>::value)>);
static_assert(std::is_same_v<bool const, decltype(std::is_virtual_base_of_v<Base, Derived>)>);
}

// Test their value
{
static_assert(std::is_virtual_base_of<Base, Derived>::value == expected);
static_assert(std::is_virtual_base_of<const Base, Derived>::value == expected);
static_assert(std::is_virtual_base_of<Base, const Derived>::value == expected);
static_assert(std::is_virtual_base_of<const Base, const Derived>::value == expected);

static_assert(std::is_virtual_base_of_v<Base, Derived> == expected);
static_assert(std::is_virtual_base_of_v<const Base, Derived> == expected);
static_assert(std::is_virtual_base_of_v<Base, const Derived> == expected);
static_assert(std::is_virtual_base_of_v<const Base, const Derived> == expected);
}

// Check the relationship with is_base_of. If it's not a base of, it can't be a virtual base of.
{ static_assert(!std::is_base_of_v<Base, Derived> ? !std::is_virtual_base_of_v<Base, Derived> : true); }

// Make sure they can be referenced at runtime
{
bool const& a = std::is_virtual_base_of<Base, Derived>::value;
bool const& b = std::is_virtual_base_of_v<Base, Derived>;
assert(a == expected);
assert(b == expected);
}
}

struct Incomplete;
struct Unrelated {};
union IncompleteUnion;
union Union {
int i;
float f;
};

class Base {};
class Derived : Base {};
class Derived2 : Base {};
class Derived2a : Derived {};
class Derived2b : Derived {};
class Derived3Virtual : virtual Derived2a, virtual Derived2b {};

struct DerivedTransitiveViaNonVirtual : Derived3Virtual {};
struct DerivedTransitiveViaVirtual : virtual Derived3Virtual {};

template <typename T>
struct CrazyDerived : T {};
template <typename T>
struct CrazyDerivedVirtual : virtual T {};

struct DerivedPrivate : private virtual Base {};
struct DerivedProtected : protected virtual Base {};
struct DerivedPrivatePrivate : private DerivedPrivate {};
struct DerivedPrivateProtected : private DerivedProtected {};
struct DerivedProtectedPrivate : protected DerivedProtected {};
struct DerivedProtectedProtected : protected DerivedProtected {};
struct DerivedTransitivePrivate : private Derived, private Derived2 {};

int main(int, char**) {
// Test with non-virtual inheritance
{
test<false, Base, Base>();
test<false, Base, Derived>();
test<false, Base, Derived2>();
test<false, Derived, DerivedTransitivePrivate>();
test<false, Derived, Base>();
test<false, Incomplete, Derived>();

// Derived must be a complete type if Base and Derived are non-union class types
// test<false, Base, Incomplete>();
}

// Test with virtual inheritance
{
test<false, Base, Derived3Virtual>();
test<false, Derived, Derived3Virtual>();
test<true, Derived2b, Derived3Virtual>();
test<true, Derived2a, Derived3Virtual>();
test<true, Base, DerivedPrivate>();
test<true, Base, DerivedProtected>();
test<true, Base, DerivedPrivatePrivate>();
test<true, Base, DerivedPrivateProtected>();
test<true, Base, DerivedProtectedPrivate>();
test<true, Base, DerivedProtectedProtected>();
test<true, Derived2a, DerivedTransitiveViaNonVirtual>();
test<true, Derived2b, DerivedTransitiveViaNonVirtual>();
test<true, Derived2a, DerivedTransitiveViaVirtual>();
test<true, Derived2b, DerivedTransitiveViaVirtual>();
test<false, Base, CrazyDerived<Base>>();
test<false, CrazyDerived<Base>, Base>();
test<true, Base, CrazyDerivedVirtual<Base>>();
test<false, CrazyDerivedVirtual<Base>, Base>();
}

// Test unrelated types
{
test<false, Base&, Derived&>();
test<false, Base[3], Derived[3]>();
test<false, Unrelated, Derived>();
test<false, Base, Unrelated>();
test<false, Base, void>();
test<false, void, Derived>();
}

// Test scalar types
{
test<false, int, Base>();
test<false, int, Derived>();
test<false, int, Incomplete>();
test<false, int, int>();

test<false, Base, int>();
test<false, Derived, int>();
test<false, Incomplete, int>();

test<false, int[], int[]>();
test<false, long, int>();
test<false, int, long>();
}

// Test unions
{
test<false, Union, Union>();
test<false, IncompleteUnion, IncompleteUnion>();
test<false, Union, IncompleteUnion>();
test<false, IncompleteUnion, Union>();
test<false, Incomplete, IncompleteUnion>();
test<false, IncompleteUnion, Incomplete>();
test<false, Unrelated, IncompleteUnion>();
test<false, IncompleteUnion, Unrelated>();
test<false, int, IncompleteUnion>();
test<false, IncompleteUnion, int>();
test<false, Unrelated, Union>();
test<false, Union, Unrelated>();
test<false, int, Unrelated>();
test<false, Union, int>();
}

return 0;
}
3 changes: 2 additions & 1 deletion libcxx/utils/generate_feature_test_macro_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -784,7 +784,8 @@ def add_version_header(tc):
"c++26": 202406 # P2985R0 A type trait for detecting virtual base classes
},
"headers": ["type_traits"],
"unimplemented": True,
"test_suite_guard": "__has_builtin(__builtin_is_virtual_base_of)",
"libcxx_guard": "__has_builtin(__builtin_is_virtual_base_of)",
},
{
"name": "__cpp_lib_is_within_lifetime",
Expand Down
Loading