[libcxx] r296565 - Improve diagnostics when an invalid hash is used in an unordered container.

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Tue Feb 28 18:02:28 PST 2017


Author: ericwf
Date: Tue Feb 28 20:02:28 2017
New Revision: 296565

URL: http://llvm.org/viewvc/llvm-project?rev=296565&view=rev
Log:
Improve diagnostics when an invalid hash is used in an unordered container.

This patch adds a static assertion that the specified hash meets
the requirements of an enabled hash, and it ensures that the static
assertion is evaluated before __compressed_pair is instantiated.
That way the static assertion diagnostic is emitted first.

Added:
    libcxx/trunk/test/libcxx/containers/unord/unord.set/missing_hash_specialization.fail.cpp
Modified:
    libcxx/trunk/include/__hash_table

Modified: libcxx/trunk/include/__hash_table
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__hash_table?rev=296565&r1=296564&r2=296565&view=diff
==============================================================================
--- libcxx/trunk/include/__hash_table (original)
+++ libcxx/trunk/include/__hash_table Tue Feb 28 20:02:28 2017
@@ -871,11 +871,20 @@ public:
 template <class _Key, class _Hash, class _Equal, class _Alloc>
 struct __diagnose_hash_table_helper {
   static constexpr bool __trigger_diagnostics()
-  _LIBCPP_DIAGNOSE_WARNING(!__invokable<_Hash const&, _Key const&>::value,
-    "the specified hash functor does not provide a const call operator")
-  _LIBCPP_DIAGNOSE_WARNING(!__invokable<_Equal const&, _Key const&, _Key const&>::value,
-    "the specified comparator type does not provide a const call operator")
-  { return true; }
+    _LIBCPP_DIAGNOSE_WARNING(__has_enabled_hash<_Key, _Hash>::value
+                         && !__invokable<_Hash const&, _Key const&>::value,
+      "the specified hash functor does not provide a const call operator")
+    _LIBCPP_DIAGNOSE_WARNING(is_copy_constructible<_Equal>::value
+                          && !__invokable<_Equal const&, _Key const&, _Key const&>::value,
+      "the specified comparator type does not provide a const call operator")
+  {
+    static_assert(__has_enabled_hash<_Key, _Hash>::value,
+      "the specified hash functor does not meet the requirements for an "
+      "enabled hash");
+    static_assert(is_copy_constructible<_Equal>::value,
+      "the specified comparator is required to be copy constructible");
+    return true;
+  }
 };
 
 template <class _Key, class _Value, class _Hash, class _Equal, class _Alloc>
@@ -951,6 +960,10 @@ private:
     typedef allocator_traits<__pointer_allocator>          __pointer_alloc_traits;
     typedef typename __bucket_list_deleter::pointer       __node_pointer_pointer;
 
+#ifndef _LIBCPP_CXX03_LANG
+    static_assert(__diagnose_hash_table_helper<_Tp, _Hash, _Equal, _Alloc>::__trigger_diagnostics(), "");
+#endif
+
     // --- Member data begin ---
     __bucket_list                                         __bucket_list_;
     __compressed_pair<__first_node, __node_allocator>     __p1_;
@@ -1482,13 +1495,13 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::~__hash_table()
 {
+#if defined(_LIBCPP_CXX03_LANG)
     static_assert((is_copy_constructible<key_equal>::value),
                  "Predicate must be copy-constructible.");
     static_assert((is_copy_constructible<hasher>::value),
                  "Hasher must be copy-constructible.");
-#ifndef _LIBCPP_CXX03_LANG
-    static_assert(__diagnose_hash_table_helper<_Tp, _Hash, _Equal, _Alloc>::__trigger_diagnostics(), "");
 #endif
+
     __deallocate_node(__p1_.first().__next_);
 #if _LIBCPP_DEBUG_LEVEL >= 2
     __get_db()->__erase_c(this);

Added: libcxx/trunk/test/libcxx/containers/unord/unord.set/missing_hash_specialization.fail.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/containers/unord/unord.set/missing_hash_specialization.fail.cpp?rev=296565&view=auto
==============================================================================
--- libcxx/trunk/test/libcxx/containers/unord/unord.set/missing_hash_specialization.fail.cpp (added)
+++ libcxx/trunk/test/libcxx/containers/unord/unord.set/missing_hash_specialization.fail.cpp Tue Feb 28 20:02:28 2017
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+// REQUIRES: diagnose-if-support
+
+// <unordered_set>
+
+// Test that we generate a reasonable diagnostic when the specified hash is
+// not enabled.
+
+#include <unordered_set>
+#include <utility>
+
+using VT = std::pair<int, int>;
+using Set = std::unordered_set<VT>;
+
+int main() {
+
+  Set s; // expected-error at __hash_table:* {{the specified hash functor does not meet the requirements for an enabled hash}}
+
+  // FIXME: It would be great to suppress the below diagnostic all together.
+  //        but for now it's sufficient that it appears last. However there is
+  //        currently no way to test the order diagnostics are issued.
+  // expected-error at memory:* {{call to implicitly-deleted default constructor of 'std::__1::hash<std::__1::pair<int, int> >'}}
+}




More information about the cfe-commits mailing list