summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/__hash_table36
-rw-r--r--include/__tree11
-rw-r--r--include/type_traits9
-rw-r--r--include/unordered_map8
-rw-r--r--test/libcxx/containers/associative/non_const_comparator.fail.cpp4
-rw-r--r--test/libcxx/containers/unord/non_const_comparator.fail.cpp56
6 files changed, 100 insertions, 24 deletions
diff --git a/include/__hash_table b/include/__hash_table
index e082e6c81..6d6a6a1aa 100644
--- a/include/__hash_table
+++ b/include/__hash_table
@@ -18,6 +18,7 @@
#include <algorithm>
#include <cmath>
#include <utility>
+#include <type_traits>
#include <__undef_min_max>
@@ -38,6 +39,15 @@ template <class _Key, class _Tp>
struct __hash_value_type;
#endif
+template <class _Key, class _Cp, class _Hash,
+ bool = is_empty<_Hash>::value && !__libcpp_is_final<_Hash>::value>
+class __unordered_map_hasher;
+
+template <class _Key, class _Cp, class _Pred,
+ bool = is_empty<_Pred>::value && !__libcpp_is_final<_Pred>::value
+ >
+class __unordered_map_equal;
+
#ifndef _LIBCPP_CXX03_LANG
template <class _Tp>
struct __is_hash_value_type_imp : false_type {};
@@ -856,6 +866,29 @@ public:
template <class> friend class __hash_map_node_destructor;
};
+
+#ifndef _LIBCPP_CXX03_LANG
+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; }
+};
+
+template <class _Key, class _Value, class _Hash, class _Equal, class _Alloc>
+struct __diagnose_hash_table_helper<
+ __hash_value_type<_Key, _Value>,
+ __unordered_map_hasher<_Key, __hash_value_type<_Key, _Value>, _Hash>,
+ __unordered_map_equal<_Key, __hash_value_type<_Key, _Value>, _Equal>,
+ _Alloc>
+: __diagnose_hash_table_helper<_Key, _Hash, _Equal, _Alloc>
+{
+};
+#endif // _LIBCPP_CXX03_LANG
+
template <class _Tp, class _Hash, class _Equal, class _Alloc>
class __hash_table
{
@@ -1453,6 +1486,9 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::~__hash_table()
"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/include/__tree b/include/__tree
index 3bc020734..170d4c0b3 100644
--- a/include/__tree
+++ b/include/__tree
@@ -963,7 +963,7 @@ private:
template <class _Tp, class _Compare, class _Allocator>
struct __diagnose_tree_helper {
static constexpr bool __trigger_diagnostics()
- _LIBCPP_DIAGNOSE_WARNING(!__is_const_comparable<_Compare, _Tp>::value,
+ _LIBCPP_DIAGNOSE_WARNING(!__invokable<_Compare const&, _Tp const&, _Tp const&>::value,
"the specified comparator type does not provide a const call operator")
{ return true; }
};
@@ -973,15 +973,10 @@ struct __diagnose_tree_helper<
__value_type<_Key, _Value>,
__map_value_compare<_Key, __value_type<_Key, _Value>, _KeyComp>,
_Alloc
->
+> : __diagnose_tree_helper<_Key, _KeyComp, _Alloc>
{
- static constexpr bool __trigger_diagnostics()
- _LIBCPP_DIAGNOSE_WARNING(!__is_const_comparable<_KeyComp, _Key>::value,
- "the specified comparator type does not provide a const call operator")
- { return true; }
};
-
-#endif
+#endif // !_LIBCPP_CXX03_LANG
template <class _Tp, class _Compare, class _Allocator>
class __tree
diff --git a/include/type_traits b/include/type_traits
index 8812d3d32..786295560 100644
--- a/include/type_traits
+++ b/include/type_traits
@@ -4715,15 +4715,6 @@ struct __can_extract_map_key<_ValTy, _Key, _Key, _RawValTy>
#endif
-template <class _Comp, class _ValueType, class = void>
-struct __is_const_comparable : false_type {};
-
-template <class _Comp, class _ValueType>
-struct __is_const_comparable<_Comp, _ValueType, typename __void_t<
- decltype(_VSTD::declval<_Comp const&>()(_VSTD::declval<_ValueType const&>(),
- _VSTD::declval<_ValueType const&>()))
- >::type> : true_type {};
-
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_TYPE_TRAITS
diff --git a/include/unordered_map b/include/unordered_map
index 7baf63883..3f3808c1e 100644
--- a/include/unordered_map
+++ b/include/unordered_map
@@ -379,9 +379,7 @@ template <class Key, class T, class Hash, class Pred, class Alloc>
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Key, class _Cp, class _Hash,
- bool = is_empty<_Hash>::value && !__libcpp_is_final<_Hash>::value
- >
+template <class _Key, class _Cp, class _Hash, bool _IsEmpty>
class __unordered_map_hasher
: private _Hash
{
@@ -449,9 +447,7 @@ swap(__unordered_map_hasher<_Key, _Cp, _Hash, __b>& __x,
__x.swap(__y);
}
-template <class _Key, class _Cp, class _Pred,
- bool = is_empty<_Pred>::value && !__libcpp_is_final<_Pred>::value
- >
+template <class _Key, class _Cp, class _Pred, bool _IsEmpty>
class __unordered_map_equal
: private _Pred
{
diff --git a/test/libcxx/containers/associative/non_const_comparator.fail.cpp b/test/libcxx/containers/associative/non_const_comparator.fail.cpp
index 239a7542f..ea0d9ac09 100644
--- a/test/libcxx/containers/associative/non_const_comparator.fail.cpp
+++ b/test/libcxx/containers/associative/non_const_comparator.fail.cpp
@@ -24,7 +24,9 @@ struct BadCompare {
};
int main() {
- static_assert(!std::__is_const_comparable<BadCompare, int>::value, "");
+ static_assert(!std::__invokable<BadCompare const&, int const&, int const&>::value, "");
+ static_assert(std::__invokable<BadCompare&, int const&, int const&>::value, "");
+
// expected-warning@__tree:* 4 {{the specified comparator type does not provide a const call operator}}
{
using C = std::set<int, BadCompare>;
diff --git a/test/libcxx/containers/unord/non_const_comparator.fail.cpp b/test/libcxx/containers/unord/non_const_comparator.fail.cpp
new file mode 100644
index 000000000..8adc67589
--- /dev/null
+++ b/test/libcxx/containers/unord/non_const_comparator.fail.cpp
@@ -0,0 +1,56 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, verify-support
+
+// Test that libc++ generates a warning diagnostic when the container is
+// provided a non-const callable comparator.
+
+#include <unordered_set>
+#include <unordered_map>
+
+struct BadHash {
+ template <class T>
+ size_t operator()(T const& t) {
+ return std::hash<T>{}(t);
+ }
+};
+
+struct BadEqual {
+ template <class T, class U>
+ bool operator()(T const& t, U const& u) {
+ return t == u;
+ }
+};
+
+int main() {
+ static_assert(!std::__invokable<BadEqual const&, int const&, int const&>::value, "");
+ static_assert(std::__invokable<BadEqual&, int const&, int const&>::value, "");
+
+ // expected-warning@__hash_table:* 4 {{the specified comparator type does not provide a const call operator}}
+ // expected-warning@__hash_table:* 4 {{the specified hash functor does not provide a const call operator}}
+
+ {
+ using C = std::unordered_set<int, BadHash, BadEqual>;
+ C s;
+ }
+ {
+ using C = std::unordered_multiset<long, BadHash, BadEqual>;
+ C s;
+ }
+ {
+ using C = std::unordered_map<int, int, BadHash, BadEqual>;
+ C s;
+ }
+ {
+ using C = std::unordered_multimap<long, int, BadHash, BadEqual>;
+ C s;
+ }
+}