summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Fiselier <eric@efcs.ca>2017-03-01 02:02:28 +0000
committerEric Fiselier <eric@efcs.ca>2017-03-01 02:02:28 +0000
commitc6422362d5f9683f7e1003fe244b3fe84d6cca6f (patch)
treedb50ebf653a791d4ca1e77ac643b8c4f0b87415f
parent67f7a781263dad0b1ea54eb2d2afb00f2fd938ef (diff)
downloadexternal_libcxx-c6422362d5f9683f7e1003fe244b3fe84d6cca6f.tar.gz
external_libcxx-c6422362d5f9683f7e1003fe244b3fe84d6cca6f.tar.bz2
external_libcxx-c6422362d5f9683f7e1003fe244b3fe84d6cca6f.zip
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. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@296565 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/__hash_table27
-rw-r--r--test/libcxx/containers/unord/unord.set/missing_hash_specialization.fail.cpp32
2 files changed, 52 insertions, 7 deletions
diff --git a/include/__hash_table b/include/__hash_table
index 6d6a6a1aa..9d9a29055 100644
--- a/include/__hash_table
+++ b/include/__hash_table
@@ -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>::__hash_table(__hash_table&& __u,
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);
diff --git a/test/libcxx/containers/unord/unord.set/missing_hash_specialization.fail.cpp b/test/libcxx/containers/unord/unord.set/missing_hash_specialization.fail.cpp
new file mode 100644
index 000000000..8a9cde700
--- /dev/null
+++ b/test/libcxx/containers/unord/unord.set/missing_hash_specialization.fail.cpp
@@ -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@__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@memory:* {{call to implicitly-deleted default constructor of 'std::__1::hash<std::__1::pair<int, int> >'}}
+}