1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_TEMPLATE_UTIL_H_ 6 #define BASE_TEMPLATE_UTIL_H_ 7 8 #include <stddef.h> 9 #include <iosfwd> 10 #include <type_traits> 11 #include <utility> 12 13 #include "build/build_config.h" 14 15 // This hacks around libstdc++ 4.6 missing stuff in type_traits, while we need 16 // to support it. 17 #define CR_GLIBCXX_4_7_0 20120322 18 #define CR_GLIBCXX_4_5_4 20120702 19 #define CR_GLIBCXX_4_6_4 20121127 20 #if defined(__GLIBCXX__) && \ 21 (__GLIBCXX__ < CR_GLIBCXX_4_7_0 || __GLIBCXX__ == CR_GLIBCXX_4_5_4 || \ 22 __GLIBCXX__ == CR_GLIBCXX_4_6_4) 23 #define CR_USE_FALLBACKS_FOR_OLD_GLIBCXX 24 #endif 25 26 // Some versions of libstdc++ have partial support for type_traits, but misses 27 // a smaller subset while removing some of the older non-standard stuff. Assume 28 // that all versions below 5.0 fall in this category, along with one 5.0 29 // experimental release. Test for this by consulting compiler major version, 30 // the only reliable option available, so theoretically this could fail should 31 // you attempt to mix an earlier version of libstdc++ with >= GCC5. But 32 // that's unlikely to work out, especially as GCC5 changed ABI. 33 #define CR_GLIBCXX_5_0_0 20150123 34 #if (defined(__GNUC__) && __GNUC__ < 5) || \ 35 (defined(__GLIBCXX__) && __GLIBCXX__ == CR_GLIBCXX_5_0_0) 36 #define CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX 37 #endif 38 39 // This hacks around using gcc with libc++ which has some incompatibilies. 40 // - is_trivially_* doesn't work: https://llvm.org/bugs/show_bug.cgi?id=27538 41 // TODO(danakj): Remove this when android builders are all using a newer version 42 // of gcc, or the android ndk is updated to a newer libc++ that works with older 43 // gcc versions. 44 #if !defined(__clang__) && defined(_LIBCPP_VERSION) 45 #define CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX 46 #endif 47 48 namespace base { 49 50 template <class T> struct is_non_const_reference : std::false_type {}; 51 template <class T> struct is_non_const_reference<T&> : std::true_type {}; 52 template <class T> struct is_non_const_reference<const T&> : std::false_type {}; 53 54 namespace internal { 55 56 // Uses expression SFINAE to detect whether using operator<< would work. 57 template <typename T, typename = void> 58 struct SupportsOstreamOperator : std::false_type {}; 59 template <typename T> 60 struct SupportsOstreamOperator<T, 61 decltype(void(std::declval<std::ostream&>() 62 << std::declval<T>()))> 63 : std::true_type {}; 64 65 } // namespace internal 66 67 // underlying_type produces the integer type backing an enum type. 68 // TODO(crbug.com/554293): Remove this when all platforms have this in the std 69 // namespace. 70 #if defined(CR_USE_FALLBACKS_FOR_OLD_GLIBCXX) 71 template <typename T> 72 struct underlying_type { 73 using type = __underlying_type(T); 74 }; 75 #else 76 template <typename T> 77 using underlying_type = std::underlying_type<T>; 78 #endif 79 80 // TODO(crbug.com/554293): Remove this when all platforms have this in the std 81 // namespace. 82 #if defined(CR_USE_FALLBACKS_FOR_OLD_GLIBCXX) 83 template <class T> 84 using is_trivially_destructible = std::has_trivial_destructor<T>; 85 #else 86 template <class T> 87 using is_trivially_destructible = std::is_trivially_destructible<T>; 88 #endif 89 90 // is_trivially_copyable is especially hard to get right. 91 // - Older versions of libstdc++ will fail to have it like they do for other 92 // type traits. In this case we should provide it based on compiler 93 // intrinsics. This is covered by the CR_USE_FALLBACKS_FOR_OLD_GLIBCXX define. 94 // - An experimental release of gcc includes most of type_traits but misses 95 // is_trivially_copyable, so we still have to avoid using libstdc++ in this 96 // case, which is covered by CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX. 97 // - When compiling libc++ from before r239653, with a gcc compiler, the 98 // std::is_trivially_copyable can fail. So we need to work around that by not 99 // using the one in libc++ in this case. This is covered by the 100 // CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX define, and is discussed in 101 // https://llvm.org/bugs/show_bug.cgi?id=27538#c1 where they point out that 102 // in libc++'s commit r239653 this is fixed by libc++ checking for gcc 5.1. 103 // - In both of the above cases we are using the gcc compiler. When defining 104 // this ourselves on compiler intrinsics, the __is_trivially_copyable() 105 // intrinsic is not available on gcc before version 5.1 (see the discussion in 106 // https://llvm.org/bugs/show_bug.cgi?id=27538#c1 again), so we must check for 107 // that version. 108 // - When __is_trivially_copyable() is not available because we are on gcc older 109 // than 5.1, we need to fall back to something, so we use __has_trivial_copy() 110 // instead based on what was done one-off in bit_cast() previously. 111 112 // TODO(crbug.com/554293): Remove this when all platforms have this in the std 113 // namespace and it works with gcc as needed. 114 #if defined(CR_USE_FALLBACKS_FOR_OLD_GLIBCXX) || \ 115 defined(CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX) || \ 116 defined(CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX) 117 template <typename T> 118 struct is_trivially_copyable { 119 // TODO(danakj): Remove this when android builders are all using a newer version 120 // of gcc, or the android ndk is updated to a newer libc++ that does this for 121 // us. 122 #if _GNUC_VER >= 501 123 static constexpr bool value = __is_trivially_copyable(T); 124 #else 125 static constexpr bool value = __has_trivial_copy(T); 126 #endif 127 }; 128 #else 129 template <class T> 130 using is_trivially_copyable = std::is_trivially_copyable<T>; 131 #endif 132 133 } // namespace base 134 135 #undef CR_USE_FALLBACKS_FOR_OLD_GLIBCXX 136 #undef CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX 137 #undef CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX 138 139 #endif // BASE_TEMPLATE_UTIL_H_ 140