EricWF created this revision.
EricWF added a reviewer: mclow.lists.
EricWF added a subscriber: cfe-commits.

This patch removes the static_assert for non-enum types in the primary hash 
template. Instead non-enum types create a hash<T> specialization that is not 
constructible nor callable.

See also:
  * http://cplusplus.github.io/LWG/lwg-active.html#2543
  * https://llvm.org/bugs/show_bug.cgi?id=28917

https://reviews.llvm.org/D23331

Files:
  include/functional
  test/std/utilities/function.objects/unord.hash/enum.pass.cpp
  test/std/utilities/function.objects/unord.hash/non_enum.pass.cpp

Index: test/std/utilities/function.objects/unord.hash/non_enum.pass.cpp
===================================================================
--- /dev/null
+++ test/std/utilities/function.objects/unord.hash/non_enum.pass.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03, c++11
+
+// <functional>
+
+//  Hashing a struct w/o a defined hash should *not* fail, but it should
+// create a type that is not constructible and not callable.
+// See also: http://cplusplus.github.io/LWG/lwg-active.html#2543
+
+#include <functional>
+#include <cassert>
+#include <type_traits>
+
+#include "test_macros.h"
+
+struct X {};
+
+int main()
+{
+    using H = std::hash<X>;
+    static_assert(!std::is_default_constructible<H>::value, "");
+    static_assert(!std::is_copy_constructible<H>::value, "");
+    static_assert(!std::is_move_constructible<H>::value, "");
+    static_assert(!std::is_copy_assignable<H>::value, "");
+    static_assert(!std::is_move_assignable<H>::value, "");
+#if TEST_STD_VER > 14
+    static_assert(!std::is_callable<H(X&)>::value, "");
+    static_assert(!std::is_callable<H(X const&)>::value, "");
+#endif
+}
Index: test/std/utilities/function.objects/unord.hash/enum.pass.cpp
===================================================================
--- test/std/utilities/function.objects/unord.hash/enum.pass.cpp
+++ test/std/utilities/function.objects/unord.hash/enum.pass.cpp
@@ -7,15 +7,15 @@
 //
 //===----------------------------------------------------------------------===//
 
+// UNSUPPORTED: c++98, c++03, c++11
+
 // <functional>
 
 // make sure that we can hash enumeration values
 // Not very portable
 
 #include "test_macros.h"
 
-#if TEST_STD_VER >= 14
-
 #include <functional>
 #include <cassert>
 #include <type_traits>
@@ -59,6 +59,3 @@
 
     test<Fruits>();
 }
-#else
-int main () {}
-#endif
Index: include/functional
===================================================================
--- include/functional
+++ include/functional
@@ -2574,19 +2574,29 @@
 };
 
 #if _LIBCPP_STD_VER > 11
-template <class _Tp>
-struct _LIBCPP_TYPE_VIS_ONLY hash
+
+template <class _Tp, bool = is_enum<_Tp>::value>
+struct _LIBCPP_TYPE_VIS_ONLY __enum_hash
     : public unary_function<_Tp, size_t>
 {
-    static_assert(is_enum<_Tp>::value, "This hash only works for enumeration types");
-
     _LIBCPP_INLINE_VISIBILITY
     size_t operator()(_Tp __v) const _NOEXCEPT
     {
         typedef typename underlying_type<_Tp>::type type;
         return hash<type>{}(static_cast<type>(__v));
     }
 };
+template <class _Tp>
+struct _LIBCPP_TYPE_VIS_ONLY __enum_hash<_Tp, false> {
+    __enum_hash() = delete;
+    __enum_hash(__enum_hash const&) = delete;
+    __enum_hash& operator=(__enum_hash const&) = delete;
+};
+
+template <class _Tp>
+struct _LIBCPP_TYPE_VIS_ONLY hash : public __enum_hash<_Tp>
+{
+};
 #endif
 
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to