-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[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
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This trait is implemented in C++26 conditionally on the compiler supporting the __builtin_is_virtual_base_of intrinsic. I believe only tip-of-trunk Clang currently implements that builtin. Closes llvm#105432
@llvm/pr-subscribers-libcxx Author: Louis Dionne (ldionne) ChangesThis trait is implemented in C++26 conditionally on the compiler supporting the __builtin_is_virtual_base_of intrinsic. I believe only tip-of-trunk Clang currently implements that builtin. Closes #105432 Full diff: https://github.com/llvm/llvm-project/pull/105847.diff 10 Files Affected:
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index a1506e115fe70f..f6d3142c1e2d3e 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -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*
---------------------------------------------------------- -----------------
diff --git a/libcxx/docs/ReleaseNotes/20.rst b/libcxx/docs/ReleaseNotes/20.rst
index fe9f4c1973cdb4..bc28f380945bc3 100644
--- a/libcxx/docs/ReleaseNotes/20.rst
+++ b/libcxx/docs/ReleaseNotes/20.rst
@@ -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
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index dd62bcc2555ffc..d95cb11f483c00 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -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",""
diff --git a/libcxx/include/__type_traits/is_base_of.h b/libcxx/include/__type_traits/is_base_of.h
index 090abeeb54dccb..3aac3629a02521 100644
--- a/libcxx/include/__type_traits/is_base_of.h
+++ b/libcxx/include/__type_traits/is_base_of.h
@@ -26,6 +26,19 @@ 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 integral_constant<bool, __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
diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits
index 7f231cd09df510..5937d4fdc9e1a7 100644
--- a/libcxx/include/type_traits
+++ b/libcxx/include/type_traits
@@ -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
@@ -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
diff --git a/libcxx/include/version b/libcxx/include/version
index fe64343eafbc9c..a19be2d294afd3 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -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
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp
index bb69ca7368aafa..1cbf2699a95bcc 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp
@@ -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
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index b8bad696f1bae0..bd2959d55dc20d 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -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
diff --git a/libcxx/test/std/utilities/meta/meta.rel/is_virtual_base_of.pass.cpp b/libcxx/test/std/utilities/meta/meta.rel/is_virtual_base_of.pass.cpp
new file mode 100644
index 00000000000000..6b34d56e2c6f45
--- /dev/null
+++ b/libcxx/test/std/utilities/meta/meta.rel/is_virtual_base_of.pass.cpp
@@ -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;
+}
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index b041b08f02aac5..f402d4de2275e5 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -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",
|
philnik777
approved these changes
Aug 24, 2024
H-G-Hristov
added a commit
to H-G-Hristov/llvm-project
that referenced
this pull request
Sep 2, 2024
…e_traits.inc` `std::is_virtual_base_of` was implemented in llvm#105847
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This trait is implemented in C++26 conditionally on the compiler supporting the __builtin_is_virtual_base_of intrinsic. I believe only tip-of-trunk Clang currently implements that builtin.
Closes #105432