]> granicus.if.org Git - llvm/commitdiff
Fix llvm::is_trivially_copyable portability issues
authorSerge Guelton <sguelton@quarkslab.com>
Tue, 22 Jan 2019 13:48:55 +0000 (13:48 +0000)
committerSerge Guelton <sguelton@quarkslab.com>
Tue, 22 Jan 2019 13:48:55 +0000 (13:48 +0000)
llvm::is_trivially_copyable portability is verified at compile time using
std::is_trivially_copyable as the reference implementation.

Unfortunately, the latter is not available on all platforms, so introduce
a proper configure check to detect if it is available on the target platform.

In a similar manner, std::is_copy_assignable is not fully supported for gcc4.9.
Provide a portable (?) implementation instead.

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351820 91177308-0d34-0410-b5e6-96231b3b80d8

cmake/config-ix.cmake
include/llvm/ADT/PointerIntPair.h
include/llvm/Config/config.h.cmake
include/llvm/Support/type_traits.h

index 30ee2b9cbb68dfb5ce8b6e8520cd97d8db046a2a..9e9e28f067308595a9b59865b4e55abd93e5b788 100644 (file)
@@ -325,6 +325,15 @@ else()
   unset(HAVE_FFI_CALL CACHE)
 endif( LLVM_ENABLE_FFI )
 
+# Whether we can use std::is_trivially_copyable to verify llvm::is_trivially_copyable.
+CHECK_CXX_SOURCE_COMPILES("
+#include <type_traits>
+struct T { int val; };
+static_assert(std::is_trivially_copyable<T>::value, \"ok\");
+int main() { return 0;}
+" HAVE_STD_IS_TRIVIALLY_COPYABLE)
+
+
 # Define LLVM_HAS_ATOMICS if gcc or MSVC atomic builtins are supported.
 include(CheckAtomic)
 
index b132de819874103c1fd8e89cbcb6820c662d6b21..24a2bb67a36e2cbeee28dc2ddbf5815c72d55021 100644 (file)
@@ -14,6 +14,7 @@
 #define LLVM_ADT_POINTERINTPAIR_H
 
 #include "llvm/Support/PointerLikeTypeTraits.h"
+#include "llvm/Support/type_traits.h"
 #include <cassert>
 #include <cstdint>
 #include <limits>
@@ -125,6 +126,19 @@ public:
   }
 };
 
+// Specialize is_trivially_copyable to avoid limitation of llvm::is_trivially_copyable
+// when compiled with gcc 4.9.
+template <typename PointerTy, unsigned IntBits, typename IntType,
+          typename PtrTraits,
+          typename Info>
+struct is_trivially_copyable<PointerIntPair<PointerTy, IntBits, IntType, PtrTraits, Info>> : std::true_type {
+#ifdef HAVE_STD_IS_TRIVIALLY_COPYABLE
+  static_assert(std::is_trivially_copyable<PointerIntPair<PointerTy, IntBits, IntType, PtrTraits, Info>>::value,
+                "inconsistent behavior between llvm:: and std:: implementation of is_trivially_copyable");
+#endif
+};
+
+
 template <typename PointerT, unsigned IntBits, typename PtrTraits>
 struct PointerIntPairInfo {
   static_assert(PtrTraits::NumLowBitsAvailable <
index 03bbd74d6d325e1b42b095801eb9e2e3e7521c68..a66d0fa070a315cc95148f23f2ededb48df455fe 100644 (file)
 /* Define as the return type of signal handlers (`int' or `void'). */
 #cmakedefine RETSIGTYPE ${RETSIGTYPE}
 
+/* Define if std::is_trivially_copyable is supported */
+#cmakedefine HAVE_STD_IS_TRIVIALLY_COPYABLE ${HAVE_STD_IS_TRIVIALLY_COPYABLE}
+
 /* Define to a function implementing stricmp */
 #cmakedefine stricmp ${stricmp}
 
index b8cf12d03d286e16d5711775a7c2899186b53ee4..1ceeedd7856d071430d818ac34367fee8e6b6a62 100644 (file)
@@ -95,6 +95,7 @@ template<class T>
 union trivial_helper {
     T t;
 };
+
 } // end namespace detail
 
 /// An implementation of `std::is_trivially_copy_constructible` since we have
@@ -119,6 +120,24 @@ struct is_trivially_move_constructible<T &> : std::true_type {};
 template <typename T>
 struct is_trivially_move_constructible<T &&> : std::true_type {};
 
+
+template <typename T>
+struct is_copy_assignable {
+  template<class F>
+    static auto get(F*) -> decltype(std::declval<T &>() = std::declval<const T &>(), std::true_type{});
+    static std::false_type get(...);
+    static constexpr bool value = decltype(get((T*)nullptr))::value;
+};
+
+template <typename T>
+struct is_move_assignable {
+  template<class F>
+    static auto get(F*) -> decltype(std::declval<T &>() = std::declval<T &&>(), std::true_type{});
+    static std::false_type get(...);
+    static constexpr bool value = decltype(get((T*)nullptr))::value;
+};
+
+
 // An implementation of `std::is_trivially_copyable` since STL version
 // is not equally supported by all compilers, especially GCC 4.9.
 // Uniform implementation of this trait is important for ABI compatibility
@@ -140,15 +159,15 @@ class is_trivially_copyable {
 
   // copy assign
   static constexpr bool has_trivial_copy_assign =
-      std::is_copy_assignable<detail::trivial_helper<T>>::value;
+      is_copy_assignable<detail::trivial_helper<T>>::value;
   static constexpr bool has_deleted_copy_assign =
-      !std::is_copy_assignable<T>::value;
+      !is_copy_assignable<T>::value;
 
   // move assign
   static constexpr bool has_trivial_move_assign =
-      std::is_move_assignable<detail::trivial_helper<T>>::value;
+      is_move_assignable<detail::trivial_helper<T>>::value;
   static constexpr bool has_deleted_move_assign =
-      !std::is_move_assignable<T>::value;
+      !is_move_assignable<T>::value;
 
   // destructor
   static constexpr bool has_trivial_destructor =
@@ -163,10 +182,14 @@ class is_trivially_copyable {
       (has_deleted_copy_assign || has_trivial_copy_assign) &&
       (has_deleted_copy_constructor || has_trivial_copy_constructor);
 
-#if (__has_feature(is_trivially_copyable) || (defined(__GNUC__) && __GNUC__ >= 5))
-  static_assert(value == std::is_trivially_copyable<T>::value, "inconsistent behavior between llvm:: and std:: implementation of is_trivially_copyable");
+#ifdef HAVE_STD_IS_TRIVIALLY_COPYABLE
+  static_assert(value == std::is_trivially_copyable<T>::value,
+                "inconsistent behavior between llvm:: and std:: implementation of is_trivially_copyable");
 #endif
 };
+template <typename T>
+class is_trivially_copyable<T*> : public std::true_type {
+};
 
 
 } // end namespace llvm