1 //===- llvm/Support/type_traits.h - Simplfied type traits -------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file provides useful additions to the standard type_traits library. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_SUPPORT_TYPE_TRAITS_H 14 #define LLVM_SUPPORT_TYPE_TRAITS_H 15 16 #include "llvm/Support/Compiler.h" 17 #include <type_traits> 18 #include <utility> 19 20 #ifndef __has_feature 21 #define LLVM_DEFINED_HAS_FEATURE 22 #define __has_feature(x) 0 23 #endif 24 25 namespace llvm { 26 27 28 /// Metafunction that determines whether the given type is either an 29 /// integral type or an enumeration type, including enum classes. 30 /// 31 /// Note that this accepts potentially more integral types than is_integral 32 /// because it is based on being implicitly convertible to an integral type. 33 /// Also note that enum classes aren't implicitly convertible to integral types, 34 /// the value may therefore need to be explicitly converted before being used. 35 template <typename T> class is_integral_or_enum { 36 using UnderlyingT = typename std::remove_reference<T>::type; 37 38 public: 39 static const bool value = 40 !std::is_class<UnderlyingT>::value && // Filter conversion operators. 41 !std::is_pointer<UnderlyingT>::value && 42 !std::is_floating_point<UnderlyingT>::value && 43 (std::is_enum<UnderlyingT>::value || 44 std::is_convertible<UnderlyingT, unsigned long long>::value); 45 }; 46 47 /// If T is a pointer, just return it. If it is not, return T&. 48 template<typename T, typename Enable = void> 49 struct add_lvalue_reference_if_not_pointer { using type = T &; }; 50 51 template <typename T> 52 struct add_lvalue_reference_if_not_pointer< 53 T, typename std::enable_if<std::is_pointer<T>::value>::type> { 54 using type = T; 55 }; 56 57 /// If T is a pointer to X, return a pointer to const X. If it is not, 58 /// return const T. 59 template<typename T, typename Enable = void> 60 struct add_const_past_pointer { using type = const T; }; 61 62 template <typename T> 63 struct add_const_past_pointer< 64 T, typename std::enable_if<std::is_pointer<T>::value>::type> { 65 using type = const typename std::remove_pointer<T>::type *; 66 }; 67 68 template <typename T, typename Enable = void> 69 struct const_pointer_or_const_ref { 70 using type = const T &; 71 }; 72 template <typename T> 73 struct const_pointer_or_const_ref< 74 T, typename std::enable_if<std::is_pointer<T>::value>::type> { 75 using type = typename add_const_past_pointer<T>::type; 76 }; 77 78 namespace detail { 79 /// Internal utility to detect trivial copy construction. 80 template<typename T> union copy_construction_triviality_helper { 81 T t; 82 copy_construction_triviality_helper() = default; 83 copy_construction_triviality_helper(const copy_construction_triviality_helper&) = default; 84 ~copy_construction_triviality_helper() = default; 85 }; 86 /// Internal utility to detect trivial move construction. 87 template<typename T> union move_construction_triviality_helper { 88 T t; 89 move_construction_triviality_helper() = default; 90 move_construction_triviality_helper(move_construction_triviality_helper&&) = default; 91 ~move_construction_triviality_helper() = default; 92 }; 93 94 template<class T> 95 union trivial_helper { 96 T t; 97 }; 98 99 } // end namespace detail 100 101 /// An implementation of `std::is_trivially_copy_constructible` since we have 102 /// users with STLs that don't yet include it. 103 template <typename T> 104 struct is_trivially_copy_constructible 105 : std::is_copy_constructible< 106 ::llvm::detail::copy_construction_triviality_helper<T>> {}; 107 template <typename T> 108 struct is_trivially_copy_constructible<T &> : std::true_type {}; 109 template <typename T> 110 struct is_trivially_copy_constructible<T &&> : std::false_type {}; 111 112 /// An implementation of `std::is_trivially_move_constructible` since we have 113 /// users with STLs that don't yet include it. 114 template <typename T> 115 struct is_trivially_move_constructible 116 : std::is_move_constructible< 117 ::llvm::detail::move_construction_triviality_helper<T>> {}; 118 template <typename T> 119 struct is_trivially_move_constructible<T &> : std::true_type {}; 120 template <typename T> 121 struct is_trivially_move_constructible<T &&> : std::true_type {}; 122 123 124 template <typename T> 125 struct is_copy_assignable { 126 template<class F> 127 static auto get(F*) -> decltype(std::declval<F &>() = std::declval<const F &>(), std::true_type{}); 128 static std::false_type get(...); 129 static constexpr bool value = decltype(get((T*)nullptr))::value; 130 }; 131 132 template <typename T> 133 struct is_move_assignable { 134 template<class F> 135 static auto get(F*) -> decltype(std::declval<F &>() = std::declval<F &&>(), std::true_type{}); 136 static std::false_type get(...); 137 static constexpr bool value = decltype(get((T*)nullptr))::value; 138 }; 139 140 141 // An implementation of `std::is_trivially_copyable` since STL version 142 // is not equally supported by all compilers, especially GCC 4.9. 143 // Uniform implementation of this trait is important for ABI compatibility 144 // as it has an impact on SmallVector's ABI (among others). 145 template <typename T> 146 class is_trivially_copyable { 147 148 // copy constructors 149 static constexpr bool has_trivial_copy_constructor = 150 std::is_copy_constructible<detail::trivial_helper<T>>::value; 151 static constexpr bool has_deleted_copy_constructor = 152 !std::is_copy_constructible<T>::value; 153 154 // move constructors 155 static constexpr bool has_trivial_move_constructor = 156 std::is_move_constructible<detail::trivial_helper<T>>::value; 157 static constexpr bool has_deleted_move_constructor = 158 !std::is_move_constructible<T>::value; 159 160 // copy assign 161 static constexpr bool has_trivial_copy_assign = 162 is_copy_assignable<detail::trivial_helper<T>>::value; 163 static constexpr bool has_deleted_copy_assign = 164 !is_copy_assignable<T>::value; 165 166 // move assign 167 static constexpr bool has_trivial_move_assign = 168 is_move_assignable<detail::trivial_helper<T>>::value; 169 static constexpr bool has_deleted_move_assign = 170 !is_move_assignable<T>::value; 171 172 // destructor 173 static constexpr bool has_trivial_destructor = 174 std::is_destructible<detail::trivial_helper<T>>::value; 175 176 public: 177 178 static constexpr bool value = 179 has_trivial_destructor && 180 (has_deleted_move_assign || has_trivial_move_assign) && 181 (has_deleted_move_constructor || has_trivial_move_constructor) && 182 (has_deleted_copy_assign || has_trivial_copy_assign) && 183 (has_deleted_copy_constructor || has_trivial_copy_constructor); 184 185 #ifdef HAVE_STD_IS_TRIVIALLY_COPYABLE 186 static_assert(value == std::is_trivially_copyable<T>::value, 187 "inconsistent behavior between llvm:: and std:: implementation of is_trivially_copyable"); 188 #endif 189 }; 190 template <typename T> 191 class is_trivially_copyable<T*> : public std::true_type { 192 }; 193 194 195 } // end namespace llvm 196 197 // If the compiler supports detecting whether a class is final, define 198 // an LLVM_IS_FINAL macro. If it cannot be defined properly, this 199 // macro will be left undefined. 200 #if __cplusplus >= 201402L || defined(_MSC_VER) 201 #define LLVM_IS_FINAL(Ty) std::is_final<Ty>() 202 #elif __has_feature(is_final) || LLVM_GNUC_PREREQ(4, 7, 0) 203 #define LLVM_IS_FINAL(Ty) __is_final(Ty) 204 #endif 205 206 #ifdef LLVM_DEFINED_HAS_FEATURE 207 #undef __has_feature 208 #endif 209 210 #endif // LLVM_SUPPORT_TYPE_TRAITS_H 211