summaryrefslogtreecommitdiff
path: root/libstdc++-v3
diff options
context:
space:
mode:
authorville <ville@138bc75d-0d04-0410-961f-82ee72b054a4>2017-01-21 15:38:23 +0000
committerville <ville@138bc75d-0d04-0410-961f-82ee72b054a4>2017-01-21 15:38:23 +0000
commitf59d23d2284ef9a28134be7782e0acc991680cd5 (patch)
treec4dd133b3f3bc23f7e1a1395c9e1fc10b1c2fde0 /libstdc++-v3
parentef14ca404784aaf946c93d8776910a982129b962 (diff)
downloadgcc-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/ChangeLog15
-rw-r--r--libstdc++-v3/include/bits/functional_hash.h2
-rw-r--r--libstdc++-v3/include/std/optional21
-rw-r--r--libstdc++-v3/include/std/variant27
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/hash.cc6
-rw-r--r--libstdc++-v3/testsuite/20_util/variant/hash.cc11
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()
{