mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-27 03:48:33 +00:00
Diagnose non-const-callable hash functions and comparators
llvm-svn: 291969
This commit is contained in:
parent
c0431fd02d
commit
04333f9bda
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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>;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user