Author: ericwf Date: Fri Jan 13 16:42:53 2017 New Revision: 291969 URL: http://llvm.org/viewvc/llvm-project?rev=291969&view=rev Log: Diagnose non-const-callable hash functions and comparators
Added: libcxx/trunk/test/libcxx/containers/unord/non_const_comparator.fail.cpp Modified: libcxx/trunk/include/__hash_table libcxx/trunk/include/__tree libcxx/trunk/include/type_traits libcxx/trunk/include/unordered_map libcxx/trunk/test/libcxx/containers/associative/non_const_comparator.fail.cpp Modified: libcxx/trunk/include/__hash_table URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__hash_table?rev=291969&r1=291968&r2=291969&view=diff ============================================================================== --- libcxx/trunk/include/__hash_table (original) +++ libcxx/trunk/include/__hash_table Fri Jan 13 16:42:53 2017 @@ -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> "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); Modified: libcxx/trunk/include/__tree URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__tree?rev=291969&r1=291968&r2=291969&view=diff ============================================================================== --- libcxx/trunk/include/__tree (original) +++ libcxx/trunk/include/__tree Fri Jan 13 16:42:53 2017 @@ -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 Modified: libcxx/trunk/include/type_traits URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/type_traits?rev=291969&r1=291968&r2=291969&view=diff ============================================================================== --- libcxx/trunk/include/type_traits (original) +++ libcxx/trunk/include/type_traits Fri Jan 13 16:42:53 2017 @@ -4715,15 +4715,6 @@ struct __can_extract_map_key<_ValTy, _Ke #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 Modified: libcxx/trunk/include/unordered_map URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/unordered_map?rev=291969&r1=291968&r2=291969&view=diff ============================================================================== --- libcxx/trunk/include/unordered_map (original) +++ libcxx/trunk/include/unordered_map Fri Jan 13 16:42:53 2017 @@ -379,9 +379,7 @@ template <class Key, class T, class Hash _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, _ __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 { Modified: libcxx/trunk/test/libcxx/containers/associative/non_const_comparator.fail.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/containers/associative/non_const_comparator.fail.cpp?rev=291969&r1=291968&r2=291969&view=diff ============================================================================== --- libcxx/trunk/test/libcxx/containers/associative/non_const_comparator.fail.cpp (original) +++ libcxx/trunk/test/libcxx/containers/associative/non_const_comparator.fail.cpp Fri Jan 13 16:42:53 2017 @@ -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>; Added: libcxx/trunk/test/libcxx/containers/unord/non_const_comparator.fail.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/containers/unord/non_const_comparator.fail.cpp?rev=291969&view=auto ============================================================================== --- libcxx/trunk/test/libcxx/containers/unord/non_const_comparator.fail.cpp (added) +++ libcxx/trunk/test/libcxx/containers/unord/non_const_comparator.fail.cpp Fri Jan 13 16:42:53 2017 @@ -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; + } +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits