Implement P0513R0, Poisoning the Hash.
* include/bits/functional_hash.h (__poison_hash): New. * include/bits/unique_ptr.h (hash<unique_ptr<_Tp, _Dp>>): Derive from __poison_hash. * include/std/optional (hash<optional<_Tp>>): Likewise. * include/std/variant (hash<variant<_Types...>>): Likewise. * testsuite/20_util/default_delete/48631_neg.cc: Adjust. * testsuite/20_util/default_delete/void_neg.cc: Likewise. * testsuite/20_util/optional/hash.cc: New. * testsuite/20_util/unique_ptr/assign/48635_neg.cc: Adjust. * testsuite/20_util/unique_ptr/cons/cv_qual_neg.cc: Adjust. * testsuite/20_util/unique_ptr/hash/1.cc: Add tests for poisoned fancy pointer hashes. * testsuite/20_util/variant/hash.cc: New. From-SVN: r242402
This commit is contained in:
parent
627a2f5923
commit
6964bb3ed9
12 changed files with 141 additions and 7 deletions
|
@ -1,3 +1,20 @@
|
|||
2016-11-14 Ville Voutilainen <ville.voutilainen@gmail.com>
|
||||
|
||||
Implement P0513R0, Poisoning the Hash.
|
||||
* include/bits/functional_hash.h (__poison_hash): New.
|
||||
* include/bits/unique_ptr.h
|
||||
(hash<unique_ptr<_Tp, _Dp>>): Derive from __poison_hash.
|
||||
* include/std/optional (hash<optional<_Tp>>): Likewise.
|
||||
* include/std/variant (hash<variant<_Types...>>): Likewise.
|
||||
* testsuite/20_util/default_delete/48631_neg.cc: Adjust.
|
||||
* testsuite/20_util/default_delete/void_neg.cc: Likewise.
|
||||
* testsuite/20_util/optional/hash.cc: New.
|
||||
* testsuite/20_util/unique_ptr/assign/48635_neg.cc: Adjust.
|
||||
* testsuite/20_util/unique_ptr/cons/cv_qual_neg.cc: Adjust.
|
||||
* testsuite/20_util/unique_ptr/hash/1.cc: Add tests for
|
||||
poisoned fancy pointer hashes.
|
||||
* testsuite/20_util/variant/hash.cc: New.
|
||||
|
||||
2016-11-14 Ville Voutilainen <ville.voutilainen@gmail.com>
|
||||
|
||||
Implement P0504R0 (Revisiting in-place tag types for
|
||||
|
|
|
@ -57,6 +57,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
template<typename _Tp>
|
||||
struct hash;
|
||||
|
||||
template<typename _Tp, typename = void>
|
||||
struct __poison_hash
|
||||
{
|
||||
private:
|
||||
// Private rather than deleted to be non-trivially-copyable.
|
||||
__poison_hash(__poison_hash&&);
|
||||
~__poison_hash();
|
||||
};
|
||||
|
||||
template<typename _Tp>
|
||||
struct __poison_hash<_Tp, __void_t<decltype(hash<_Tp>()(declval<_Tp>()))>>
|
||||
{
|
||||
};
|
||||
|
||||
// Helper struct for SFINAE-poisoning non-enum types.
|
||||
template<typename _Tp, bool = is_enum<_Tp>::value>
|
||||
struct __hash_enum
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <utility>
|
||||
#include <tuple>
|
||||
#include <bits/stl_function.h>
|
||||
#include <bits/functional_hash.h>
|
||||
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
{
|
||||
|
@ -763,7 +764,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
/// std::hash specialization for unique_ptr.
|
||||
template<typename _Tp, typename _Dp>
|
||||
struct hash<unique_ptr<_Tp, _Dp>>
|
||||
: public __hash_base<size_t, unique_ptr<_Tp, _Dp>>
|
||||
: public __hash_base<size_t, unique_ptr<_Tp, _Dp>>,
|
||||
private __poison_hash<typename unique_ptr<_Tp, _Dp>::pointer>
|
||||
{
|
||||
size_t
|
||||
operator()(const unique_ptr<_Tp, _Dp>& __u) const noexcept
|
||||
|
|
|
@ -943,7 +943,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
// Hash.
|
||||
template<typename _Tp>
|
||||
struct hash<optional<_Tp>>
|
||||
struct hash<optional<_Tp>> : private __poison_hash<remove_const_t<_Tp>>
|
||||
{
|
||||
using result_type = size_t;
|
||||
using argument_type = optional<_Tp>;
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include <bits/functexcept.h>
|
||||
#include <bits/move.h>
|
||||
#include <bits/uses_allocator.h>
|
||||
#include <bits/functional_hash.h>
|
||||
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
{
|
||||
|
@ -1337,6 +1338,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
template<typename... _Types>
|
||||
struct hash<variant<_Types...>>
|
||||
: private __poison_hash<remove_const_t<_Types>>...
|
||||
{
|
||||
using result_type = size_t;
|
||||
using argument_type = variant<_Types...>;
|
||||
|
|
|
@ -26,4 +26,4 @@ struct D : B { };
|
|||
D d;
|
||||
std::default_delete<B[]> db;
|
||||
typedef decltype(db(&d)) type; // { dg-error "no match" }
|
||||
// { dg-error "no type" "" { target *-*-* } 107 }
|
||||
// { dg-error "no type" "" { target *-*-* } 108 }
|
||||
|
|
|
@ -25,5 +25,5 @@ void test01()
|
|||
{
|
||||
std::default_delete<void> d;
|
||||
d(nullptr); // { dg-error "here" }
|
||||
// { dg-error "incomplete" "" { target *-*-* } 73 }
|
||||
// { dg-error "incomplete" "" { target *-*-* } 74 }
|
||||
}
|
||||
|
|
38
libstdc++-v3/testsuite/20_util/optional/hash.cc
Normal file
38
libstdc++-v3/testsuite/20_util/optional/hash.cc
Normal file
|
@ -0,0 +1,38 @@
|
|||
// { dg-options "-std=gnu++17" }
|
||||
|
||||
// Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a moved_to of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <optional>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
class S{}; // No hash specialization
|
||||
|
||||
template<class T>
|
||||
auto f(int) -> decltype(std::hash<std::optional<T>>(), std::true_type());
|
||||
|
||||
template<class T>
|
||||
auto f(...) -> decltype(std::false_type());
|
||||
|
||||
static_assert(!decltype(f<S>(0))::value, "");
|
||||
|
||||
int main()
|
||||
{
|
||||
int x = 42;
|
||||
std::optional<int> x2 = 42;
|
||||
VERIFY(std::hash<int>()(x) == std::hash<std::optional<int>>()(x2));
|
||||
}
|
|
@ -42,10 +42,10 @@ void f()
|
|||
std::unique_ptr<int, D&> ud(nullptr, d);
|
||||
ub = std::move(ud); // { dg-error "no match" }
|
||||
ub2 = ud; // { dg-error "no match" }
|
||||
// { dg-error "no type" "" { target *-*-* } 288 }
|
||||
// { dg-error "no type" "" { target *-*-* } 289 }
|
||||
|
||||
std::unique_ptr<int[], B&> uba(nullptr, b);
|
||||
std::unique_ptr<int[], D&> uda(nullptr, d);
|
||||
uba = std::move(uda); // { dg-error "no match" }
|
||||
// { dg-error "no type" "" { target *-*-* } 539 }
|
||||
// { dg-error "no type" "" { target *-*-* } 540 }
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ test07()
|
|||
std::unique_ptr<const A[]> cA3(p); // { dg-error "no matching function" }
|
||||
std::unique_ptr<volatile A[]> vA3(p); // { dg-error "no matching function" }
|
||||
std::unique_ptr<const volatile A[]> cvA3(p); // { dg-error "no matching function" }
|
||||
// { dg-error "no type" "" { target *-*-* } 447 }
|
||||
// { dg-error "no type" "" { target *-*-* } 448 }
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
|
|
@ -21,6 +21,29 @@
|
|||
|
||||
#include <memory>
|
||||
#include <testsuite_hooks.h>
|
||||
#include <testsuite_allocator.h>
|
||||
|
||||
// User-defined pointer type that throws if a null pointer is dereferenced.
|
||||
template<typename T>
|
||||
struct Pointer : __gnu_test::PointerBase<Pointer<T>, T>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct PointerDeleter : std::default_delete<T>
|
||||
{
|
||||
typedef Pointer<T> pointer;
|
||||
void operator()(pointer) const;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
auto f(int) -> decltype(std::hash<std::unique_ptr<T,
|
||||
PointerDeleter<T>>>(), std::true_type());
|
||||
|
||||
template<class T>
|
||||
auto f(...) -> decltype(std::false_type());
|
||||
|
||||
static_assert(!decltype(f<Pointer<int>>(0))::value, "");
|
||||
|
||||
void test01()
|
||||
{
|
||||
|
|
38
libstdc++-v3/testsuite/20_util/variant/hash.cc
Normal file
38
libstdc++-v3/testsuite/20_util/variant/hash.cc
Normal file
|
@ -0,0 +1,38 @@
|
|||
// { dg-options "-std=gnu++17" }
|
||||
|
||||
// Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a moved_to of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <variant>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
class S{}; // No hash specialization
|
||||
|
||||
template<class T>
|
||||
auto f(int) -> decltype(std::hash<std::variant<T>>(), std::true_type());
|
||||
|
||||
template<class T>
|
||||
auto f(...) -> decltype(std::false_type());
|
||||
|
||||
static_assert(!decltype(f<S>(0))::value, "");
|
||||
|
||||
int main()
|
||||
{
|
||||
int x = 42;
|
||||
std::variant<int> x2 = 42;
|
||||
VERIFY(std::hash<int>()(x) == std::hash<std::variant<int>>()(x2));
|
||||
}
|
Loading…
Add table
Reference in a new issue