From: Ville Voutilainen Date: Mon, 14 Nov 2016 21:22:53 +0000 (+0200) Subject: Implement P0513R0, Poisoning the Hash. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=6964bb3ed962554b18ca92633b5395f91f9bebac;p=gcc.git Implement P0513R0, Poisoning the Hash. * include/bits/functional_hash.h (__poison_hash): New. * include/bits/unique_ptr.h (hash>): Derive from __poison_hash. * include/std/optional (hash>): Likewise. * include/std/variant (hash>): 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 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index fd309713686..d3da57cc9a4 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,20 @@ +2016-11-14 Ville Voutilainen + + Implement P0513R0, Poisoning the Hash. + * include/bits/functional_hash.h (__poison_hash): New. + * include/bits/unique_ptr.h + (hash>): Derive from __poison_hash. + * include/std/optional (hash>): Likewise. + * include/std/variant (hash>): 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 Implement P0504R0 (Revisiting in-place tag types for diff --git a/libstdc++-v3/include/bits/functional_hash.h b/libstdc++-v3/include/bits/functional_hash.h index def35f589e4..dc096831869 100644 --- a/libstdc++-v3/include/bits/functional_hash.h +++ b/libstdc++-v3/include/bits/functional_hash.h @@ -57,6 +57,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct hash; + template + struct __poison_hash + { + private: + // Private rather than deleted to be non-trivially-copyable. + __poison_hash(__poison_hash&&); + ~__poison_hash(); + }; + + template + struct __poison_hash<_Tp, __void_t()(declval<_Tp>()))>> + { + }; + // Helper struct for SFINAE-poisoning non-enum types. template::value> struct __hash_enum diff --git a/libstdc++-v3/include/bits/unique_ptr.h b/libstdc++-v3/include/bits/unique_ptr.h index 996c9eac3c3..f9ec60f769b 100644 --- a/libstdc++-v3/include/bits/unique_ptr.h +++ b/libstdc++-v3/include/bits/unique_ptr.h @@ -36,6 +36,7 @@ #include #include #include +#include namespace std _GLIBCXX_VISIBILITY(default) { @@ -763,7 +764,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// std::hash specialization for unique_ptr. template struct hash> - : public __hash_base> + : public __hash_base>, + private __poison_hash::pointer> { size_t operator()(const unique_ptr<_Tp, _Dp>& __u) const noexcept diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional index 35b6932fc98..ac73ea75bae 100644 --- a/libstdc++-v3/include/std/optional +++ b/libstdc++-v3/include/std/optional @@ -943,7 +943,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Hash. template - struct hash> + struct hash> : private __poison_hash> { using result_type = size_t; using argument_type = optional<_Tp>; diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant index 0d5fa56670b..6f3f67c5780 100644 --- a/libstdc++-v3/include/std/variant +++ b/libstdc++-v3/include/std/variant @@ -41,6 +41,7 @@ #include #include #include +#include namespace std _GLIBCXX_VISIBILITY(default) { @@ -1337,6 +1338,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct hash> + : private __poison_hash>... { using result_type = size_t; using argument_type = variant<_Types...>; diff --git a/libstdc++-v3/testsuite/20_util/default_delete/48631_neg.cc b/libstdc++-v3/testsuite/20_util/default_delete/48631_neg.cc index 23b3f8b6c46..2f99b25758b 100644 --- a/libstdc++-v3/testsuite/20_util/default_delete/48631_neg.cc +++ b/libstdc++-v3/testsuite/20_util/default_delete/48631_neg.cc @@ -26,4 +26,4 @@ struct D : B { }; D d; std::default_delete db; typedef decltype(db(&d)) type; // { dg-error "no match" } -// { dg-error "no type" "" { target *-*-* } 107 } +// { dg-error "no type" "" { target *-*-* } 108 } diff --git a/libstdc++-v3/testsuite/20_util/default_delete/void_neg.cc b/libstdc++-v3/testsuite/20_util/default_delete/void_neg.cc index c9688bcda7b..74aa32f7cb0 100644 --- a/libstdc++-v3/testsuite/20_util/default_delete/void_neg.cc +++ b/libstdc++-v3/testsuite/20_util/default_delete/void_neg.cc @@ -25,5 +25,5 @@ void test01() { std::default_delete d; d(nullptr); // { dg-error "here" } - // { dg-error "incomplete" "" { target *-*-* } 73 } + // { dg-error "incomplete" "" { target *-*-* } 74 } } diff --git a/libstdc++-v3/testsuite/20_util/optional/hash.cc b/libstdc++-v3/testsuite/20_util/optional/hash.cc new file mode 100644 index 00000000000..294a6174cdb --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/optional/hash.cc @@ -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 +// . + +#include +#include + +class S{}; // No hash specialization + +template +auto f(int) -> decltype(std::hash>(), std::true_type()); + +template +auto f(...) -> decltype(std::false_type()); + +static_assert(!decltype(f(0))::value, ""); + +int main() +{ + int x = 42; + std::optional x2 = 42; + VERIFY(std::hash()(x) == std::hash>()(x2)); +} diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/assign/48635_neg.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/assign/48635_neg.cc index 9d248265be9..e9655f13750 100644 --- a/libstdc++-v3/testsuite/20_util/unique_ptr/assign/48635_neg.cc +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/assign/48635_neg.cc @@ -42,10 +42,10 @@ void f() std::unique_ptr 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 uba(nullptr, b); std::unique_ptr uda(nullptr, d); uba = std::move(uda); // { dg-error "no match" } -// { dg-error "no type" "" { target *-*-* } 539 } +// { dg-error "no type" "" { target *-*-* } 540 } } diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/cv_qual_neg.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/cv_qual_neg.cc index a0f77c0c009..3e6f41bd8da 100644 --- a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/cv_qual_neg.cc +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/cv_qual_neg.cc @@ -39,7 +39,7 @@ test07() std::unique_ptr cA3(p); // { dg-error "no matching function" } std::unique_ptr vA3(p); // { dg-error "no matching function" } std::unique_ptr cvA3(p); // { dg-error "no matching function" } - // { dg-error "no type" "" { target *-*-* } 447 } + // { dg-error "no type" "" { target *-*-* } 448 } } template diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/hash/1.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/hash/1.cc index 6fc4fdc809d..ae73a43cfb3 100644 --- a/libstdc++-v3/testsuite/20_util/unique_ptr/hash/1.cc +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/hash/1.cc @@ -21,6 +21,29 @@ #include #include +#include + +// User-defined pointer type that throws if a null pointer is dereferenced. +template +struct Pointer : __gnu_test::PointerBase, T> +{ +}; + +template +struct PointerDeleter : std::default_delete +{ + typedef Pointer pointer; + void operator()(pointer) const; +}; + +template +auto f(int) -> decltype(std::hash>>(), std::true_type()); + +template +auto f(...) -> decltype(std::false_type()); + +static_assert(!decltype(f>(0))::value, ""); void test01() { diff --git a/libstdc++-v3/testsuite/20_util/variant/hash.cc b/libstdc++-v3/testsuite/20_util/variant/hash.cc new file mode 100644 index 00000000000..74f97edd235 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/variant/hash.cc @@ -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 +// . + +#include +#include + +class S{}; // No hash specialization + +template +auto f(int) -> decltype(std::hash>(), std::true_type()); + +template +auto f(...) -> decltype(std::false_type()); + +static_assert(!decltype(f(0))::value, ""); + +int main() +{ + int x = 42; + std::variant x2 = 42; + VERIFY(std::hash()(x) == std::hash>()(x2)); +}