diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 77a83d273af..c37cab49396 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,16 @@ 2019-05-10 Jonathan Wakely + PR libstdc++/90388 + * include/bits/unique_ptr.h (default_delete, default_delete): + Use _Require for constraints. + (operator>(nullptr_t, const unique_ptr&)): Implement exactly as + per the standard. + (__uniq_ptr_hash): New base class with conditionally-disabled call + operator. + (hash>): Derive from __uniq_ptr_hash. + * testsuite/20_util/default_delete/48631_neg.cc: Adjust dg-error line. + * testsuite/20_util/unique_ptr/hash/90388.cc: New test. + * include/bits/shared_ptr.h: Improve docs. * include/bits/shared_ptr_base.h: Likewise. * include/bits/stl_uninitialized.h: Likewise. diff --git a/libstdc++-v3/include/bits/unique_ptr.h b/libstdc++-v3/include/bits/unique_ptr.h index 6a23669f119..a9e74725dfd 100644 --- a/libstdc++-v3/include/bits/unique_ptr.h +++ b/libstdc++-v3/include/bits/unique_ptr.h @@ -66,8 +66,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * Allows conversion from a deleter for objects of another type, `_Up`, * only if `_Up*` is convertible to `_Tp*`. */ - template::value>::type> + template>> default_delete(const default_delete<_Up>&) noexcept { } /// Calls `delete __ptr` @@ -102,19 +102,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * it is undefined to `delete[]` an array of derived types through a * pointer to the base type. */ - template::value>::type> + template>> default_delete(const default_delete<_Up[]>&) noexcept { } /// Calls `delete[] __ptr` template - typename enable_if::value>::type + typename enable_if::value>::type operator()(_Up* __ptr) const - { - static_assert(sizeof(_Tp)>0, - "can't delete pointer to incomplete type"); - delete [] __ptr; - } + { + static_assert(sizeof(_Tp)>0, + "can't delete pointer to incomplete type"); + delete [] __ptr; + } }; /// @cond undocumented @@ -712,7 +712,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION unique_ptr<_Tp, _Dp>&) = delete; #endif - /// Equality operator for unique_ptr objects, compares the owned pointers. + /// Equality operator for unique_ptr objects, compares the owned pointers template _GLIBCXX_NODISCARD inline bool @@ -848,23 +848,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_NODISCARD inline bool operator>=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) { return !(nullptr < __x); } + // @} relates unique_ptr + + /// @cond undocumented + template::__enable_hash_call> + struct __uniq_ptr_hash +#if ! _GLIBCXX_INLINE_VERSION + : private __poison_hash<_Ptr> +#endif + { + size_t + operator()(const _Up& __u) const + noexcept(noexcept(std::declval>()(std::declval<_Ptr>()))) + { return hash<_Ptr>()(__u.get()); } + }; + + template + struct __uniq_ptr_hash<_Up, _Ptr, false> + : private __poison_hash<_Ptr> + { }; + /// @endcond /// std::hash specialization for unique_ptr. template struct hash> : public __hash_base>, - private __poison_hash::pointer> - { - size_t - operator()(const unique_ptr<_Tp, _Dp>& __u) const noexcept - { - typedef unique_ptr<_Tp, _Dp> _UP; - return std::hash()(__u.get()); - } - }; + public __uniq_ptr_hash> + { }; #if __cplusplus > 201103L - + /// @relates unique_ptr @{ #define __cpp_lib_make_unique 201304 /// @cond undocumented @@ -899,9 +913,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template inline typename _MakeUniq<_Tp>::__invalid_type make_unique(_Args&&...) = delete; + // @} relates unique_ptr #endif - // @} relates unique_ptr // @} group pointer_abstractions #if __cplusplus >= 201703L 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 bd81913c651..111a42434db 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 *-*-* } 111 } +// { dg-error "no type" "" { target *-*-* } 112 } diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/hash/90388.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/hash/90388.cc new file mode 100644 index 00000000000..0f3b7857797 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/hash/90388.cc @@ -0,0 +1,90 @@ +// Copyright (C) 2019 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 copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-do run { target c++11 } } + +#include + +template + struct is_callable + : std::false_type + { }; + +template + struct is_callable()(std::declval())))> + : std::true_type + { }; + +void +test01() +{ + struct D { + struct pointer { }; + void operator()(pointer) const noexcept { } + }; + static_assert( !is_callable&, D::pointer>::value ); + + using UP = std::unique_ptr; + // [unord.hash] + // Disabled specializations of hash are not function object types + static_assert( !is_callable&, UP>::value ); + static_assert( !is_callable&, UP&>::value ); + static_assert( !is_callable&, const UP&>::value ); +} + +struct D { + struct pointer { }; + void operator()(pointer) const noexcept { } +}; + +bool operator==(D::pointer, std::nullptr_t) { return false; } +bool operator!=(D::pointer, std::nullptr_t) { return true; } + +namespace std { + template<> struct hash { + size_t operator()(D::pointer) const { throw 1; } + }; +} + +void +test02() +{ + using UP = std::unique_ptr; + UP p; + std::hash h; + try { + // [util.smartptr.hash] + // The member functions are not guaranteed to be noexcept. + h(p); + throw "should not reach here"; + } catch (int) { + // Should catch exception here, rather than terminating. + } + + // Should still be noexcept if the underlying hash object is: + using UP2 = std::unique_ptr; + UP2 p2; + std::hash h2; + static_assert( noexcept(h2(p2)), "operator() is noexcept" ); +} + +int +main() +{ + test02(); +}