Introduce base::is_trivially_copyable and use for bit_cast

bit_cast had some one-off preprocessor logic to check or not to check
for the types being trivially copyable that ended up not being enabled
at all on windows.

Since most of our platforms are now C++11 make that the norm and cover
the various edge cases via base::is_trivially_copyable. Then bit_cast
can use that and will be able to static_assert for this on all platforms.

R=dcheng
BUG=555754

Review-Url: https://codereview.chromium.org/2583353002
Cr-Commit-Position: refs/heads/master@{#440491}
diff --git a/base/bit_cast.h b/base/bit_cast.h
index c9514bc..90dd925 100644
--- a/base/bit_cast.h
+++ b/base/bit_cast.h
@@ -9,6 +9,7 @@
 #include <type_traits>
 
 #include "base/compiler_specific.h"
+#include "base/template_util.h"
 #include "build/build_config.h"
 
 // bit_cast<Dest,Source> is a template function that implements the equivalent
@@ -63,34 +64,10 @@
 inline Dest bit_cast(const Source& source) {
   static_assert(sizeof(Dest) == sizeof(Source),
                 "bit_cast requires source and destination to be the same size");
-
-#if (__GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1) || \
-     (defined(__clang__) && defined(_LIBCPP_VERSION)))
-  // GCC 5.1 contains the first libstdc++ with is_trivially_copyable.
-  // Assume libc++ Just Works: is_trivially_copyable added on May 13th 2011.
-  // However, with libc++ when GCC is the compiler the trait is buggy, see
-  // crbug.com/607158, so fall back to the less strict variant for non-clang.
-  static_assert(std::is_trivially_copyable<Dest>::value,
-                "non-trivially-copyable bit_cast is undefined");
-  static_assert(std::is_trivially_copyable<Source>::value,
-                "non-trivially-copyable bit_cast is undefined");
-#elif HAS_FEATURE(is_trivially_copyable)
-  // The compiler supports an equivalent intrinsic.
-  static_assert(__is_trivially_copyable(Dest),
-                "non-trivially-copyable bit_cast is undefined");
-  static_assert(__is_trivially_copyable(Source),
-                "non-trivially-copyable bit_cast is undefined");
-#elif COMPILER_GCC
-  // Fallback to compiler intrinsic on GCC and clang (which pretends to be
-  // GCC). This isn't quite the same as is_trivially_copyable but it'll do for
-  // our purpose.
-  static_assert(__has_trivial_copy(Dest),
-                "non-trivially-copyable bit_cast is undefined");
-  static_assert(__has_trivial_copy(Source),
-                "non-trivially-copyable bit_cast is undefined");
-#else
-  // Do nothing, let the bots handle it.
-#endif
+  static_assert(base::is_trivially_copyable<Dest>::value,
+                "bit_cast requires the destination type to be copyable");
+  static_assert(base::is_trivially_copyable<Source>::value,
+                "bit_cast requires the source type to be copyable");
 
   Dest dest;
   memcpy(&dest, &source, sizeof(dest));
diff --git a/base/bit_cast_unittest.cc b/base/bit_cast_unittest.cc
index 757b0c65..f36d3fe 100644
--- a/base/bit_cast_unittest.cc
+++ b/base/bit_cast_unittest.cc
@@ -27,6 +27,5 @@
   EXPECT_EQ(1, b);
 }
 
-
 }  // namespace
 }  // namespace base
diff --git a/base/template_util.h b/base/template_util.h
index 1bfc1ac..0dc6c95 100644
--- a/base/template_util.h
+++ b/base/template_util.h
@@ -23,6 +23,23 @@
 #define CR_USE_FALLBACKS_FOR_OLD_GLIBCXX
 #endif
 
+// Some chromeos bots are using experimental 5.0 for some reason
+// which has partial support for type_traits, but misses a smaller subset
+// while removing some of the older non-standard stuff.
+#define CR_GLIBCXX_5_0_0 20150123
+#if defined(__GLIBCXX__) && (__GLIBCXX__ == CR_GLIBCXX_5_0_0)
+#define CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX
+#endif
+
+// This hacks around using gcc with libc++ which has some incompatibilies.
+// - is_trivially_* doesn't work: https://llvm.org/bugs/show_bug.cgi?id=27538
+// TODO(danakj): Remove this when android builders are all using a newer version
+// of gcc, or the android ndk is updated to a newer libc++ that works with older
+// gcc versions.
+#if !defined(__clang__) && defined(_LIBCPP_VERSION)
+#define CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX
+#endif
+
 namespace base {
 
 template <class T> struct is_non_const_reference : std::false_type {};
@@ -126,8 +143,53 @@
 using is_trivially_destructible = std::is_trivially_destructible<T>;
 #endif
 
+// is_trivially_copyable is especially hard to get right.
+// - Older versions of libstdc++ will fail to have it like they do for other
+//   type traits. In this case we should provide it based on compiler
+//   intrinsics. This is covered by the CR_USE_FALLBACKS_FOR_OLD_GLIBCXX define.
+// - An experimental release of gcc includes most of type_traits but misses
+//   is_trivially_copyable, so we still have to avoid using libstdc++ in this
+//   case, which is covered by CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX.
+// - When compiling libc++ from before r239653, with a gcc compiler, the
+//   std::is_trivially_copyable can fail. So we need to work around that by not
+//   using the one in libc++ in this case. This is covered by the
+//   CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX define, and is discussed in
+//   https://llvm.org/bugs/show_bug.cgi?id=27538#c1 where they point out that
+//   in libc++'s commit r239653 this is fixed by libc++ checking for gcc 5.1.
+// - In both of the above cases we are using the gcc compiler. When defining
+//   this ourselves on compiler intrinsics, the __is_trivially_copyable()
+//   intrinsic is not available on gcc before version 5.1 (see the discussion in
+//   https://llvm.org/bugs/show_bug.cgi?id=27538#c1 again), so we must check for
+//   that version.
+// - When __is_trivially_copyable() is not available because we are on gcc older
+//   than 5.1, we need to fall back to something, so we use __has_trivial_copy()
+//   instead based on what was done one-off in bit_cast() previously.
+
+// TODO(crbug.com/554293): Remove this when all platforms have this in the std
+// namespace and it works with gcc as needed.
+#if defined(CR_USE_FALLBACKS_FOR_OLD_GLIBCXX) ||              \
+    defined(CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX) || \
+    defined(CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX)
+template <typename T>
+struct is_trivially_copyable {
+// TODO(danakj): Remove this when android builders are all using a newer version
+// of gcc, or the android ndk is updated to a newer libc++ that does this for
+// us.
+#if _GNUC_VER >= 501
+  static constexpr bool value = __is_trivially_copyable(T);
+#else
+  static constexpr bool value = __has_trivial_copy(T);
+#endif
+};
+#else
+template <class T>
+using is_trivially_copyable = std::is_trivially_copyable<T>;
+#endif
+
 }  // namespace base
 
 #undef CR_USE_FALLBACKS_FOR_OLD_GLIBCXX
+#undef CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX
+#undef CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX
 
 #endif  // BASE_TEMPLATE_UTIL_H_