diff --git a/include/llvm/ADT/Hashing.h b/include/llvm/ADT/Hashing.h index 5efaa72705e..b2bd72e7021 100644 --- a/include/llvm/ADT/Hashing.h +++ b/include/llvm/ADT/Hashing.h @@ -113,7 +113,7 @@ public: /// differing argument types even if they would implicit promote to a common /// type without changing the value. template -typename enable_if, hash_code>::type hash_value(T value); +typename enable_if, hash_code>::type hash_value(T value); /// \brief Compute a hash_code for a pointer's address. /// @@ -349,14 +349,15 @@ inline size_t get_execution_seed() { /// reading the underlying data. It is false if values of this type must /// first be passed to hash_value, and the resulting hash_codes combined. // -// FIXME: We want to replace is_integral and is_pointer here with a predicate -// which asserts that comparing the underlying storage of two values of the -// type for equality is equivalent to comparing the two values for equality. -// For all the platforms we care about, this holds for integers and pointers, -// but there are platforms where it doesn't and we would like to support -// user-defined types which happen to satisfy this property. +// FIXME: We want to replace is_integral_or_enum and is_pointer here with +// a predicate which asserts that comparing the underlying storage of two +// values of the type for equality is equivalent to comparing the two values +// for equality. For all the platforms we care about, this holds for integers +// and pointers, but there are platforms where it doesn't and we would like to +// support user-defined types which happen to satisfy this property. template struct is_hashable_data - : integral_constant::value || is_pointer::value) && + : integral_constant::value || + is_pointer::value) && 64 % sizeof(T) == 0)> {}; // Special case std::pair to detect when both types are viable and when there @@ -732,7 +733,8 @@ inline hash_code hash_integer_value(uint64_t value) { // Declared and documented above, but defined here so that any of the hashing // infrastructure is available. template -typename enable_if, hash_code>::type hash_value(T value) { +typename enable_if, hash_code>::type +hash_value(T value) { return ::llvm::hashing::detail::hash_integer_value(value); } diff --git a/include/llvm/Support/type_traits.h b/include/llvm/Support/type_traits.h index 85d90b17f17..a76344c098f 100644 --- a/include/llvm/Support/type_traits.h +++ b/include/llvm/Support/type_traits.h @@ -121,12 +121,42 @@ template <> struct is_integral_impl : true_type {}; template struct is_integral : is_integral_impl {}; +/// \brief Metafunction that determines whether the given type is either an +/// integral type or an enumeration type. +/// +/// Note that this accepts potentially more integral types than we whitelist +/// above for is_integral, it should accept essentially anything the compiler +/// believes is an integral type. +template class is_integral_or_enum { + + // Form a return type that can only be instantiated with an integral or enum + // types (or with nullptr_t in C++11). + template struct check1_return_type { char c[2]; }; + template static check1_return_type checker1(U*); + static char checker1(...); + + // Form a return type that can only be instantiated with nullptr_t in C++11 + // mode. It's harmless in C++98 mode, but this allows us to filter nullptr_t + // when building in C++11 mode without having to detect that mode for each + // different compiler. + struct nonce {}; + template + struct check2_return_type { char c[2]; }; + template static check2_return_type checker2(U*); + static char checker2(...); + +public: + enum { + value = (sizeof(char) != sizeof(checker1((T*)0)) && + sizeof(char) == sizeof(checker2((T*)0))) + }; +}; + /// \brief Metafunction that determines whether the given type is a pointer /// type. template struct is_pointer : false_type {}; template struct is_pointer : true_type {}; - // enable_if_c - Enable/disable a template based on a metafunction template struct enable_if_c { diff --git a/unittests/ADT/HashingTest.cpp b/unittests/ADT/HashingTest.cpp index f5d6aed5b99..b148f144513 100644 --- a/unittests/ADT/HashingTest.cpp +++ b/unittests/ADT/HashingTest.cpp @@ -51,6 +51,10 @@ using namespace llvm; namespace { +enum TestEnumeration { + TE_Foo = 42, + TE_Bar = 43 +}; TEST(HashingTest, HashValueBasicTest) { int x = 42, y = 43, c = 'x'; @@ -61,7 +65,9 @@ TEST(HashingTest, HashValueBasicTest) { const volatile int cvi = 71; uintptr_t addr = reinterpret_cast(&y); EXPECT_EQ(hash_value(42), hash_value(x)); + EXPECT_EQ(hash_value(42), hash_value(TE_Foo)); EXPECT_NE(hash_value(42), hash_value(y)); + EXPECT_NE(hash_value(42), hash_value(TE_Bar)); EXPECT_NE(hash_value(42), hash_value(p)); EXPECT_EQ(hash_value(71), hash_value(i)); EXPECT_EQ(hash_value(71), hash_value(ci));