On Thu, Jun 13, 2024 at 5:32 AM Jonathan Wakely <jwak...@redhat.com> wrote: > > On 11/05/24 02:01 -0700, Ken Matsui wrote: > >This patch optimizes the compilation performance of std::is_pointer > >by dispatching to the new __is_pointer built-in trait. > > > >libstdc++-v3/ChangeLog: > > > > * include/bits/cpp_type_traits.h (__is_pointer): Use > > __is_pointer built-in trait. Optimize its implementation. > > * include/std/type_traits (is_pointer): Likewise. > > (is_pointer_v): Likewise. > > > >Co-authored-by: Jonathan Wakely <jwak...@redhat.com> > >Signed-off-by: Ken Matsui <kmat...@gcc.gnu.org> > >--- > > libstdc++-v3/include/bits/cpp_type_traits.h | 31 ++++++++++++++- > > libstdc++-v3/include/std/type_traits | 44 +++++++++++++++++---- > > 2 files changed, 66 insertions(+), 9 deletions(-) > > > >diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h > >b/libstdc++-v3/include/bits/cpp_type_traits.h > >index 59f1a1875eb..210a9ea00da 100644 > >--- a/libstdc++-v3/include/bits/cpp_type_traits.h > >+++ b/libstdc++-v3/include/bits/cpp_type_traits.h > >@@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3) > > // > > // Pointer types > > // > >+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer) > >+ template<typename _Tp, bool _IsPtr = __is_pointer(_Tp)> > >+ struct __is_pointer : __truth_type<_IsPtr> > > I was worried that reusing __is_pointer this way would cause a problem > with Clang, because it has an __is_pointer built-in and the code above > causes a warning: > > isp.cc:2:12: warning: keyword '__is_pointer' will be made available as an > identifier for the remainder of the translation unit [-Wkeyword-compat] > 2 | struct __is_pointer > | ^ > > I thought this warning meant it was only available as an identifier. > But in fact it becomes available as both an identifier and as the > built-in. > > This is what I tested: > > template<typename T, bool IsPtr = __is_pointer(T)> > struct __is_pointer > { > enum { value = IsPtr }; > }; > static_assert( __is_pointer<int*>::value, "" ); > > template<typename T> > struct is_pointer > { > static constexpr bool value = __is_pointer(T); > }; > static_assert( is_pointer<int*>::value, "" ); > > So the is_pointer template can still use the built-in even though the > name '__is_pointer' has been declared as an identifier. > > So Clang matches GCC and it works fine. Good!
Actually clang does not work the same as GCC in the end; it is much more inconsistent in what it allows. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115497 (and https://github.com/llvm/llvm-project/issues/95598). Where sometimes the usage works as a trait after the use of it as an identifier and sometimes it fails. Thanks, Andrew Pinski > > >+ { > >+ enum { __value = _IsPtr }; > >+ }; > >+#else > > template<typename _Tp> > > struct __is_pointer > > { > >@@ -377,6 +384,28 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3) > > typedef __true_type __type; > > }; > > > >+ template<typename _Tp> > >+ struct __is_pointer<_Tp* const> > > None of the other traits in bits/cpp_type_traits.h is true for > cv-qualified types, so these partial specializations make __is_pointer > the odd one out. Are they necessary? > > >+ { > >+ enum { __value = 1 }; > >+ typedef __true_type __type; > >+ }; > >+ > >+ template<typename _Tp> > >+ struct __is_pointer<_Tp* volatile> > >+ { > >+ enum { __value = 1 }; > >+ typedef __true_type __type; > >+ }; > >+ > >+ template<typename _Tp> > >+ struct __is_pointer<_Tp* const volatile> > >+ { > >+ enum { __value = 1 }; > >+ typedef __true_type __type; > >+ }; > >+#endif > >+ > > // > > // An arithmetic type is an integer type or a floating point type > > // > >@@ -387,7 +416,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3) > > > > // > > // A scalar type is an arithmetic type or a pointer type > >- // > >+ // > > template<typename _Tp> > > struct __is_scalar > > : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> > > >diff --git a/libstdc++-v3/include/std/type_traits > >b/libstdc++-v3/include/std/type_traits > >index 748fa186881..ea013b4b7bc 100644 > >--- a/libstdc++-v3/include/std/type_traits > >+++ b/libstdc++-v3/include/std/type_traits > >@@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > : public true_type { }; > > #endif > > > >- template<typename> > >- struct __is_pointer_helper > >+ /// is_pointer > >+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer) > >+ template<typename _Tp> > >+ struct is_pointer > >+ : public __bool_constant<__is_pointer(_Tp)> > >+ { }; > >+#else > >+ template<typename _Tp> > >+ struct is_pointer > > : public false_type { }; > > > > template<typename _Tp> > >- struct __is_pointer_helper<_Tp*> > >+ struct is_pointer<_Tp*> > > : public true_type { }; > > > >- /// is_pointer > > template<typename _Tp> > >- struct is_pointer > >- : public __is_pointer_helper<__remove_cv_t<_Tp>>::type > >- { }; > >+ struct is_pointer<_Tp* const> > >+ : public true_type { }; > >+ > >+ template<typename _Tp> > >+ struct is_pointer<_Tp* volatile> > >+ : public true_type { }; > >+ > >+ template<typename _Tp> > >+ struct is_pointer<_Tp* const volatile> > >+ : public true_type { }; > >+#endif > > > > /// is_lvalue_reference > > template<typename> > >@@ -3268,8 +3282,22 @@ template <typename _Tp, size_t _Num> > > inline constexpr bool is_array_v<_Tp[_Num]> = true; > > #endif > > > >+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer) > >+template <typename _Tp> > >+ inline constexpr bool is_pointer_v = __is_pointer(_Tp); > >+#else > > template <typename _Tp> > >- inline constexpr bool is_pointer_v = is_pointer<_Tp>::value; > >+ inline constexpr bool is_pointer_v = false; > >+template <typename _Tp> > >+ inline constexpr bool is_pointer_v<_Tp*> = true; > >+template <typename _Tp> > >+ inline constexpr bool is_pointer_v<_Tp* const> = true; > >+template <typename _Tp> > >+ inline constexpr bool is_pointer_v<_Tp* volatile> = true; > >+template <typename _Tp> > >+ inline constexpr bool is_pointer_v<_Tp* const volatile> = true; > >+#endif > >+ > > template <typename _Tp> > > inline constexpr bool is_lvalue_reference_v = false; > > template <typename _Tp> > >-- > >2.44.0 > > >