[libc-commits] [libc] 56ce752 - [libc][NFC] Add new is_trivially_destructible check to libc's type_traits

Mikhail R. Gadelha via libc-commits libc-commits at lists.llvm.org
Thu Aug 17 10:27:05 PDT 2023


Author: Mikhail R. Gadelha
Date: 2023-08-17T14:24:26-03:00
New Revision: 56ce7522d9b116f51578532f7855f9323338fbac

URL: https://github.com/llvm/llvm-project/commit/56ce7522d9b116f51578532f7855f9323338fbac
DIFF: https://github.com/llvm/llvm-project/commit/56ce7522d9b116f51578532f7855f9323338fbac.diff

LOG: [libc][NFC] Add new is_trivially_destructible check to libc's type_traits

This patch adds new code to check if a given object is trivially
destructible. The ifdefs where necessary to implement it in gcc, as it
doesn't have the __is_trivially_destructible builtin like clang.

In gcc, it's not enough to only call __has_trivial_destructor, see:
https://stackoverflow.com/questions/20181702/which-type-traits-cannot-be-implemented-without-compiler-hooks

This patch only adds the new check, it will be used in D150211.

Reviewed By: michaelrj, sivachandra

Differential Revision: https://reviews.llvm.org/D158033

Added: 
    

Modified: 
    libc/src/__support/CPP/type_traits.h

Removed: 
    


################################################################################
diff  --git a/libc/src/__support/CPP/type_traits.h b/libc/src/__support/CPP/type_traits.h
index 316b84c5bbf095..c547541a3c6ae6 100644
--- a/libc/src/__support/CPP/type_traits.h
+++ b/libc/src/__support/CPP/type_traits.h
@@ -11,6 +11,8 @@
 
 #include "src/__support/macros/attributes.h"
 
+#include <stddef.h> // For size_t.
+
 namespace __llvm_libc {
 namespace cpp {
 
@@ -30,6 +32,8 @@ template <typename T, T v> struct integral_constant {
 using true_type = cpp::integral_constant<bool, true>;
 using false_type = cpp::integral_constant<bool, false>;
 
+template <bool V> using bool_constant = integral_constant<bool, V>;
+
 template <class T>
 struct is_trivially_copyable
     : public integral_constant<bool, __is_trivially_copyable(T)> {};
@@ -214,6 +218,131 @@ constexpr bool
                      details::void_t<decltype(details::convertible_to_helper<T>(
                          declval<F>()))>> = true;
 
+namespace details {
+#if __has_builtin(__is_lvalue_reference) &&                                    \
+    __has_builtin(__is_rvalue_reference) && __has_builtin(__is_reference)
+
+template <typename T>
+struct is_lvalue_reference : bool_constant<__is_lvalue_reference(T)> {};
+template <typename T>
+struct is_rvalue_reference : bool_constant<__is_rvalue_reference(T)> {};
+template <typename T> struct is_reference : bool_constant<__is_reference(T)> {};
+
+#else // __has_builtin(__is_lvalue_reference) && etc...
+
+template <typename T> struct is_lvalue_reference : public false_type {};
+template <typename T> struct is_lvalue_reference<T &> : public true_type {};
+
+template <typename T> struct is_rvalue_reference : public false_type {};
+template <typename T> struct is_rvalue_reference<T &&> : public true_type {};
+
+template <typename T> struct is_reference : public false_type {};
+template <typename T> struct is_reference<T &> : public true_type {};
+template <typename T> struct is_reference<T &&> : public true_type {};
+
+#endif // __has_builtin(__is_lvalue_reference) && etc...
+
+#if __has_builtin(__remove_all_extents)
+template <typename T> using __remove_all_extents_t = __remove_all_extents(T);
+#else
+template <typename T> struct remove_all_extents {
+  typedef T type;
+};
+template <typename T> struct remove_all_extents<T[]> {
+  typedef typename remove_all_extents<T>::type type;
+};
+template <typename T, size_t _Np> struct remove_all_extents<T[_Np]> {
+  typedef typename remove_all_extents<T>::type type;
+};
+
+template <typename T>
+using __remove_all_extents_t = typename remove_all_extents<T>::type;
+#endif // __has_builtin(__remove_all_extents)
+
+#if __has_builtin(__is_function)
+
+template <typename T>
+struct is_function : integral_constant<bool, __is_function(T)> {};
+
+#else
+
+template <typename T>
+struct is_function
+    : public integral_constant<bool, !(is_reference<T>::value ||
+                                       is_const<const T>::value)> {};
+
+#endif // __has_builtin(__is_function)
+
+#if __has_builtin(__is_destructible)
+
+template <typename T>
+struct is_destructible : bool_constant<__is_destructible(T)> {};
+
+#else // __has_builtin(__is_destructible)
+
+//  if it's a reference, return true
+//  if it's a function, return false
+//  if it's   void,     return false
+//  if it's an array of unknown bound, return false
+//  Otherwise, return "declval<T&>().~T()" is well-formed
+//    where T is remove_all_extents<T>::type
+
+template <typename> struct __is_destructible_apply {
+  typedef int type;
+};
+
+template <typename T> struct __is_destructor_wellformed {
+  template <typename T1>
+  static true_type __test(
+      typename __is_destructible_apply<decltype(declval<T1 &>().~T1())>::type);
+
+  template <typename T1> static false_type __test(...);
+
+  static const bool value = decltype(__test<T>(12))::value;
+};
+
+template <typename T, bool> struct __destructible_imp;
+
+template <typename T>
+struct __destructible_imp<T, false>
+    : public integral_constant<
+          bool, __is_destructor_wellformed<__remove_all_extents_t<T>>::value> {
+};
+
+template <typename T> struct __destructible_imp<T, true> : public true_type {};
+
+template <typename T, bool> struct __destructible_false;
+template <typename T>
+struct __destructible_false<T, false>
+    : public __destructible_imp<T, is_reference<T>::value> {};
+template <typename T>
+struct __destructible_false<T, true> : public false_type {};
+
+template <typename T>
+struct is_destructible : public __destructible_false<T, is_function<T>::value> {
+};
+template <typename T> struct is_destructible<T[]> : public false_type {};
+template <> struct is_destructible<void> : public false_type {};
+
+#endif // __has_builtin(__is_destructible)
+} // namespace details
+
+#if __has_builtin(__is_trivially_destructible)
+
+template <typename T>
+struct is_trivially_destructible
+    : public integral_constant<bool, __is_trivially_destructible(T)> {};
+
+#elif __has_builtin(__has_trivial_destructor)
+
+template <typename T>
+struct is_trivially_destructible
+    : public integral_constant<
+          bool, __llvm_libc::cpp::details::is_destructible<T>::value
+                    &&__has_trivial_destructor(T)> {};
+
+#endif // __has_builtin(__is_trivially_destructible)
+
 } // namespace cpp
 } // namespace __llvm_libc
 


        


More information about the libc-commits mailing list