PR libstdc++/82262 fix std::hash<std::optional<const T>>
authorJonathan Wakely <jwakely@redhat.com>
Wed, 20 Sep 2017 13:24:45 +0000 (14:24 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Wed, 20 Sep 2017 13:24:45 +0000 (14:24 +0100)
PR libstdc++/82262
* include/std/optional (__optional_hash_call_base): Add template
parameter for remove_const_t<_Tp> and use it consistently.
* testsuite/20_util/optional/hash.cc: Test optional<const T>.

From-SVN: r253010

libstdc++-v3/ChangeLog
libstdc++-v3/include/std/optional
libstdc++-v3/testsuite/20_util/optional/hash.cc

index f9424a5..6c92731 100644 (file)
@@ -1,3 +1,10 @@
+2017-09-20  Jonathan Wakely  <jwakely@redhat.com>
+
+       PR libstdc++/82262
+       * include/std/optional (__optional_hash_call_base): Add template
+       parameter for remove_const_t<_Tp> and use it consistently.
+       * testsuite/20_util/optional/hash.cc: Test optional<const T>.
+
 2017-09-19  Jonathan Wakely  <jwakely@redhat.com>
 
        PR libstdc++/71500
index 2743ef9..2df9b54 100644 (file)
@@ -1005,23 +1005,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Hash.
 
-  template<typename _Tp, bool
-           = __poison_hash<remove_const_t<_Tp>>::__enable_hash_call>
+  template<typename _Tp, typename _Up = remove_const_t<_Tp>,
+           bool = __poison_hash<_Up>::__enable_hash_call>
     struct __optional_hash_call_base
     {
       size_t
       operator()(const optional<_Tp>& __t) const
-      noexcept(noexcept(hash<_Tp> {}(*__t)))
+      noexcept(noexcept(hash<_Up>{}(*__t)))
       {
         // We pick an arbitrary hash for disengaged optionals which hopefully
         // usual values of _Tp won't typically hash to.
         constexpr size_t __magic_disengaged_hash = static_cast<size_t>(-3333);
-        return __t ? hash<_Tp> {}(*__t) : __magic_disengaged_hash;
+        return __t ? hash<_Up>{}(*__t) : __magic_disengaged_hash;
       }
     };
 
-  template<typename _Tp>
-    struct __optional_hash_call_base<_Tp, false> {};
+  template<typename _Tp, typename _Up>
+    struct __optional_hash_call_base<_Tp, _Up, false> {};
 
   template<typename _Tp>
     struct hash<optional<_Tp>>
index c16f0b2..35ae51b 100644 (file)
@@ -29,14 +29,23 @@ template<class T>
 auto f(...) -> decltype(std::false_type());
 
 static_assert(!decltype(f<S>(0))::value, "");
-static_assert(!std::is_invocable_v<
-    std::hash<std::optional<S>>&, std::optional<S> const&> );
-static_assert(std::is_invocable_v<
-    std::hash<std::optional<int>>&, std::optional<int> const&> );
+
+template<typename T>
+constexpr bool hashable()
+{ return std::is_invocable_v<std::hash<T>&, const T&>; }
+
+static_assert(!hashable<std::optional<S>>());
+static_assert(!hashable<std::optional<const S>>());
+static_assert(hashable<std::optional<int>>());
+static_assert(hashable<std::optional<const int>>());
 
 int main()
 {
   int x = 42;
   std::optional<int> x2 = 42;
   VERIFY(std::hash<int>()(x) == std::hash<std::optional<int>>()(x2));
+
+  // PR libstdc++/82262
+  std::optional<const int> x3 = x2;
+  VERIFY(std::hash<int>()(x) == std::hash<std::optional<const int>>()(x3));
 }