From 0b0b58f2c455f00e4d7a0a2429b0e5139f5b6029 Mon Sep 17 00:00:00 2001 From: JF Bastien Date: Sat, 9 Apr 2016 20:04:34 +0000 Subject: [PATCH] =?UTF-8?q?is=5Fintegral=5For=5Fenum=20=E2=9D=A5=20enum=20?= =?UTF-8?q?class=20=E2=87=92=20hashable=20enum=20class?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: As discussed in D18775 making AtomicOrdering an enum class makes it non-hashable, which shouldn't be the case. Hashing.h defines hash_value for all is_integral_or_enum, but type_traits.h's definition of is_integral_or_enum only checks for *inplicit* conversion to integral types which leaves enum classes out and is very confusing because is_enum is true for enum classes. This patch: - Adds a check for is_enum when determining is_integral_or_enum. - Explicitly converts the value parameter in hash_value to handle enum class hashing. Note that the warning at the top of Hashing.h still applies: each execution of the program has a high probability of producing a different hash_code for a given input. Thus their values are not stable to save or persist, and should only be used during the execution for the construction of hashing datastructures. Reviewers: dberlin, chandlerc Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D18938 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@265879 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/ADT/Hashing.h | 3 ++- include/llvm/Support/type_traits.h | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/include/llvm/ADT/Hashing.h b/include/llvm/ADT/Hashing.h index de56f91eddb1..6c01b15d7f06 100644 --- a/include/llvm/ADT/Hashing.h +++ b/include/llvm/ADT/Hashing.h @@ -632,7 +632,8 @@ inline hash_code hash_integer_value(uint64_t value) { template typename std::enable_if::value, hash_code>::type hash_value(T value) { - return ::llvm::hashing::detail::hash_integer_value(value); + return ::llvm::hashing::detail::hash_integer_value( + static_cast::type>(value)); } // Declared and documented above, but defined here so that any of the hashing diff --git a/include/llvm/Support/type_traits.h b/include/llvm/Support/type_traits.h index 88385c3fae1e..2a429585201a 100644 --- a/include/llvm/Support/type_traits.h +++ b/include/llvm/Support/type_traits.h @@ -54,11 +54,12 @@ struct isPodLike > { }; /// \brief Metafunction that determines whether the given type is either an -/// integral type or an enumeration type. +/// integral type or an enumeration type, including enum classes. /// /// Note that this accepts potentially more integral types than is_integral -/// because it is based on merely being convertible implicitly to an integral -/// type. +/// because it is based on being implicitly convertible to an integral type. +/// Also note that enum classes aren't implicitly convertible to integral types, +/// the value may therefore need to be explicitly converted before being used. template class is_integral_or_enum { typedef typename std::remove_reference::type UnderlyingT; @@ -67,7 +68,8 @@ template class is_integral_or_enum { !std::is_class::value && // Filter conversion operators. !std::is_pointer::value && !std::is_floating_point::value && - std::is_convertible::value; + (std::is_enum::value || + std::is_convertible::value); }; /// \brief If T is a pointer, just return it. If it is not, return T&.