aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/ADT/Hashing.h20
-rw-r--r--include/llvm/Support/type_traits.h32
-rw-r--r--unittests/ADT/HashingTest.cpp6
3 files changed, 48 insertions, 10 deletions
diff --git a/include/llvm/ADT/Hashing.h b/include/llvm/ADT/Hashing.h
index 5efaa72705..b2bd72e702 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 T>
-typename enable_if<is_integral<T>, hash_code>::type hash_value(T value);
+typename enable_if<is_integral_or_enum<T>, 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 <typename T> struct is_hashable_data
- : integral_constant<bool, ((is_integral<T>::value || is_pointer<T>::value) &&
+ : integral_constant<bool, ((is_integral_or_enum<T>::value ||
+ is_pointer<T>::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 T>
-typename enable_if<is_integral<T>, hash_code>::type hash_value(T value) {
+typename enable_if<is_integral_or_enum<T>, 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 85d90b17f1..a76344c098 100644
--- a/include/llvm/Support/type_traits.h
+++ b/include/llvm/Support/type_traits.h
@@ -121,12 +121,42 @@ template <> struct is_integral_impl<unsigned long long> : true_type {};
template <typename T>
struct is_integral : is_integral_impl<T> {};
+/// \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 <typename T> 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 <typename U, U u = U()> struct check1_return_type { char c[2]; };
+ template <typename U> static check1_return_type<U> 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 <typename U, nonce* u = U()>
+ struct check2_return_type { char c[2]; };
+ template <typename U> static check2_return_type<U> 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 <typename T> struct is_pointer : false_type {};
template <typename T> struct is_pointer<T*> : true_type {};
-
// enable_if_c - Enable/disable a template based on a metafunction
template<bool Cond, typename T = void>
struct enable_if_c {
diff --git a/unittests/ADT/HashingTest.cpp b/unittests/ADT/HashingTest.cpp
index f5d6aed5b9..b148f14451 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<uintptr_t>(&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));