diff options
author | ville <ville@138bc75d-0d04-0410-961f-82ee72b054a4> | 2017-01-21 15:38:23 +0000 |
---|---|---|
committer | ville <ville@138bc75d-0d04-0410-961f-82ee72b054a4> | 2017-01-21 15:38:23 +0000 |
commit | f59d23d2284ef9a28134be7782e0acc991680cd5 (patch) | |
tree | c4dd133b3f3bc23f7e1a1395c9e1fc10b1c2fde0 /libstdc++-v3 | |
parent | ef14ca404784aaf946c93d8776910a982129b962 (diff) | |
download | gcc-f59d23d2284ef9a28134be7782e0acc991680cd5.tar.gz |
Make poisoned hashes SFINAE away the call operator of the hash.
* include/bits/functional_hash.h
(__poison_hash::__enable_hash_call): New.
* include/std/optional (__optional_hash_call_base): New.
(hash<optional<_Tp>>): Derive from the new base,
move the hash function into that base.
* include/std/variant (__variant_hash_call_base_impl): New.
(__variant_hash_call_base): Likewise.
(hash<variant<_Types...>>): Derive from the new base,
move the hash function into that base.
* testsuite/20_util/optional/hash.cc: Add tests for is_callable.
* testsuite/20_util/variant/hash.cc: Likewise.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@244748 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libstdc++-v3')
-rw-r--r-- | libstdc++-v3/ChangeLog | 15 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/functional_hash.h | 2 | ||||
-rw-r--r-- | libstdc++-v3/include/std/optional | 21 | ||||
-rw-r--r-- | libstdc++-v3/include/std/variant | 27 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/optional/hash.cc | 6 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/variant/hash.cc | 11 |
6 files changed, 70 insertions, 12 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index dc60d4ee528..b96185a7393 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,18 @@ +2017-01-21 Ville Voutilainen <ville.voutilainen@gmail.com> + + Make poisoned hashes SFINAE away the call operator of the hash. + * include/bits/functional_hash.h + (__poison_hash::__enable_hash_call): New. + * include/std/optional (__optional_hash_call_base): New. + (hash<optional<_Tp>>): Derive from the new base, + move the hash function into that base. + * include/std/variant (__variant_hash_call_base_impl): New. + (__variant_hash_call_base): Likewise. + (hash<variant<_Types...>>): Derive from the new base, + move the hash function into that base. + * testsuite/20_util/optional/hash.cc: Add tests for is_callable. + * testsuite/20_util/variant/hash.cc: Likewise. + 2017-01-20 Joe Seymour <joe.s@somniumtech.com> * acinclude.m4 (GLIBCXX_CHECK_SIZE_T_MANGLING): Support uint20_t. diff --git a/libstdc++-v3/include/bits/functional_hash.h b/libstdc++-v3/include/bits/functional_hash.h index 14f7fae202f..38be1724d3f 100644 --- a/libstdc++-v3/include/bits/functional_hash.h +++ b/libstdc++-v3/include/bits/functional_hash.h @@ -60,6 +60,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, typename = void> struct __poison_hash { + static constexpr bool __enable_hash_call = false; private: // Private rather than deleted to be non-trivially-copyable. __poison_hash(__poison_hash&&); @@ -69,6 +70,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp> struct __poison_hash<_Tp, __void_t<decltype(hash<_Tp>()(declval<_Tp>()))>> { + static constexpr bool __enable_hash_call = true; }; // Helper struct for SFINAE-poisoning non-enum types. diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional index 85ec91dbb95..887bf9e8397 100644 --- a/libstdc++-v3/include/std/optional +++ b/libstdc++-v3/include/std/optional @@ -951,12 +951,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return optional<_Tp> { in_place, __il, std::forward<_Args>(__args)... }; } // Hash. - template<typename _Tp> - struct hash<optional<_Tp>> : private __poison_hash<remove_const_t<_Tp>> - { - using result_type = size_t; - using argument_type = optional<_Tp>; + template<typename _Tp, bool + = __poison_hash<remove_const_t<_Tp>>::__enable_hash_call> + struct __optional_hash_call_base + { size_t operator()(const optional<_Tp>& __t) const noexcept(noexcept(hash<_Tp> {}(*__t))) @@ -968,6 +967,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } }; + template<typename _Tp> + struct __optional_hash_call_base<_Tp, false> {}; + + template<typename _Tp> + struct hash<optional<_Tp>> + : private __poison_hash<remove_const_t<_Tp>>, + public __optional_hash_call_base<_Tp> + { + using result_type = size_t; + using argument_type = optional<_Tp>; + }; + /// @} _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant index 6404fceb02b..c5138e56803 100644 --- a/libstdc++-v3/include/std/variant +++ b/libstdc++-v3/include/std/variant @@ -1273,14 +1273,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::forward<_Variants>(__variants)...); } - template<typename... _Types> - struct hash<variant<_Types...>> - : private __detail::__variant::_Variant_hash_base< - variant<_Types...>, std::index_sequence_for<_Types...>> + template<bool, typename... _Types> + struct __variant_hash_call_base_impl { - using result_type = size_t; - using argument_type = variant<_Types...>; - size_t operator()(const variant<_Types...>& __t) const noexcept((is_nothrow_callable_v<hash<decay_t<_Types>>(_Types)> && ...)) @@ -1297,6 +1292,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } }; + template<typename... _Types> + struct __variant_hash_call_base_impl<false, _Types...> {}; + + template<typename... _Types> + using __variant_hash_call_base = + __variant_hash_call_base_impl<(__poison_hash<remove_const_t<_Types>>:: + __enable_hash_call &&...), _Types...>; + + template<typename... _Types> + struct hash<variant<_Types...>> + : private __detail::__variant::_Variant_hash_base< + variant<_Types...>, std::index_sequence_for<_Types...>>, + public __variant_hash_call_base<_Types...> + { + using result_type = size_t; + using argument_type = variant<_Types...>; + }; + template<> struct hash<monostate> { diff --git a/libstdc++-v3/testsuite/20_util/optional/hash.cc b/libstdc++-v3/testsuite/20_util/optional/hash.cc index ceb862b1b38..297ea2e276b 100644 --- a/libstdc++-v3/testsuite/20_util/optional/hash.cc +++ b/libstdc++-v3/testsuite/20_util/optional/hash.cc @@ -29,6 +29,12 @@ template<class T> auto f(...) -> decltype(std::false_type()); static_assert(!decltype(f<S>(0))::value, ""); +static_assert(!std::is_callable< + std::hash<std::optional<S>>& + (std::optional<S> const&)>::value, ""); +static_assert(std::is_callable< + std::hash<std::optional<int>>& + (std::optional<int> const&)>::value, ""); int main() { diff --git a/libstdc++-v3/testsuite/20_util/variant/hash.cc b/libstdc++-v3/testsuite/20_util/variant/hash.cc index a9ebf33c24d..0a267ab68e4 100644 --- a/libstdc++-v3/testsuite/20_util/variant/hash.cc +++ b/libstdc++-v3/testsuite/20_util/variant/hash.cc @@ -33,6 +33,17 @@ static_assert(!decltype(f<std::variant<S>>(0))::value, ""); static_assert(!decltype(f<std::variant<S, S>>(0))::value, ""); static_assert(decltype(f<std::variant<int>>(0))::value, ""); static_assert(decltype(f<std::variant<int, int>>(0))::value, ""); +static_assert(!std::is_callable< + std::hash<std::variant<S>>&(std::variant<S> const&)>::value, ""); +static_assert(!std::is_callable< + std::hash<std::variant<S, int>>& + (std::variant<S, int> const&)>::value, ""); +static_assert(std::is_callable< + std::hash<std::variant<int>>& + (std::variant<int> const&)>::value, ""); +static_assert(std::is_callable< + std::hash<std::variant<int, int>>& + (std::variant<int, int> const&)>::value, ""); int main() { |