From 7663cae227b8337bbcf3355698b2aa43cb1a5f70 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Wed, 31 Aug 2016 17:57:20 +0100 Subject: [PATCH] Constrain std::shared_ptr assignment and resetting * include/bits/shared_ptr.h (_Assignable): New alias template. (shared_ptr::operator=(const shared_ptr<_Tp1>&)) (shared_ptr::operator=(shared_ptr<_Tp1>&&)) (shared_ptr::operator=(unique_ptr<_Tp1>&&)): Constrain with _Assignable. * include/bits/shared_ptr_base.h (_Assignable): New alias template. (__shared_ptr::operator=(const __shared_ptr<_Tp1>&)) (__shared_ptr::operator=(__shared_ptr<_Tp1>&&)) (__shared_ptr::operator=(unique_ptr<_Tp1>&&)): Constrain with _Assignable. (__shared_ptr::reset(_Tp1*), __shared_ptr::reset(_Tp1*, _Deleter)) (__shared_ptr::reset(_Tp1*, _Deleter, _Alloc)): Constrain with _Convertible. * testsuite/20_util/shared_ptr/cons/43820_neg.cc: Change dg-error to match on any line. * testsuite/20_util/shared_ptr/cons/void_neg.cc: Likewise. * testsuite/20_util/shared_ptr/assign/sfinae.cc: New test. * testsuite/20_util/shared_ptr/assign/shared_ptr_neg.cc: Update expected errors. Remove unnecessary code. * testsuite/20_util/shared_ptr/modifiers/reset_sfinae.cc: New test. From-SVN: r239898 --- libstdc++-v3/ChangeLog | 21 +++++ libstdc++-v3/include/bits/shared_ptr.h | 14 ++- libstdc++-v3/include/bits/shared_ptr_base.h | 16 ++-- .../20_util/shared_ptr/assign/sfinae.cc | 75 +++++++++++++++ .../shared_ptr/assign/shared_ptr_neg.cc | 18 +--- .../20_util/shared_ptr/cons/43820_neg.cc | 4 +- .../20_util/shared_ptr/cons/void_neg.cc | 2 +- .../shared_ptr/modifiers/reset_sfinae.cc | 92 +++++++++++++++++++ 8 files changed, 211 insertions(+), 31 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/shared_ptr/assign/sfinae.cc create mode 100644 libstdc++-v3/testsuite/20_util/shared_ptr/modifiers/reset_sfinae.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index d608f6bdc3f..10761e8c38a 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,26 @@ 2016-08-31 Jonathan Wakely + * include/bits/shared_ptr.h (_Assignable): New alias template. + (shared_ptr::operator=(const shared_ptr<_Tp1>&)) + (shared_ptr::operator=(shared_ptr<_Tp1>&&)) + (shared_ptr::operator=(unique_ptr<_Tp1>&&)): Constrain with + _Assignable. + * include/bits/shared_ptr_base.h (_Assignable): New alias template. + (__shared_ptr::operator=(const __shared_ptr<_Tp1>&)) + (__shared_ptr::operator=(__shared_ptr<_Tp1>&&)) + (__shared_ptr::operator=(unique_ptr<_Tp1>&&)): Constrain with + _Assignable. + (__shared_ptr::reset(_Tp1*), __shared_ptr::reset(_Tp1*, _Deleter)) + (__shared_ptr::reset(_Tp1*, _Deleter, _Alloc)): Constrain with + _Convertible. + * testsuite/20_util/shared_ptr/cons/43820_neg.cc: Change dg-error to + match on any line. + * testsuite/20_util/shared_ptr/cons/void_neg.cc: Likewise. + * testsuite/20_util/shared_ptr/assign/sfinae.cc: New test. + * testsuite/20_util/shared_ptr/assign/shared_ptr_neg.cc: Update + expected errors. Remove unnecessary code. + * testsuite/20_util/shared_ptr/modifiers/reset_sfinae.cc: New test. + * include/bits/stl_tree.h (_Rb_tree::operator=(_Rb_tree&&)): Move comparison object. * testsuite/23_containers/set/move_comparison.cc: New test. diff --git a/libstdc++-v3/include/bits/shared_ptr.h b/libstdc++-v3/include/bits/shared_ptr.h index 747b09a2155..b2523b83228 100644 --- a/libstdc++-v3/include/bits/shared_ptr.h +++ b/libstdc++-v3/include/bits/shared_ptr.h @@ -93,8 +93,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION class shared_ptr : public __shared_ptr<_Tp> { template - using _Convertible - = typename enable_if::value>::type; + using _Convertible = typename + enable_if::value>::type; + + template + using _Assignable = typename + enable_if::value, shared_ptr&>::type; public: @@ -276,7 +280,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION shared_ptr& operator=(const shared_ptr&) noexcept = default; template - shared_ptr& + _Assignable<_Tp1*> operator=(const shared_ptr<_Tp1>& __r) noexcept { this->__shared_ptr<_Tp>::operator=(__r); @@ -301,7 +305,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template - shared_ptr& + _Assignable<_Tp1*> operator=(shared_ptr<_Tp1>&& __r) noexcept { this->__shared_ptr<_Tp>::operator=(std::move(__r)); @@ -309,7 +313,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template - shared_ptr& + _Assignable::pointer> operator=(std::unique_ptr<_Tp1, _Del>&& __r) { this->__shared_ptr<_Tp>::operator=(std::move(__r)); diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h index 60b825c541e..4ae26684dbe 100644 --- a/libstdc++-v3/include/bits/shared_ptr_base.h +++ b/libstdc++-v3/include/bits/shared_ptr_base.h @@ -873,6 +873,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using _Convertible = typename enable_if::value>::type; + template + using _Assignable = typename + enable_if::value, __shared_ptr&>::type; + public: typedef _Tp element_type; @@ -983,7 +987,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr __shared_ptr(nullptr_t) noexcept : __shared_ptr() { } template - __shared_ptr& + _Assignable<_Tp1*> operator=(const __shared_ptr<_Tp1, _Lp>& __r) noexcept { _M_ptr = __r._M_ptr; @@ -1009,7 +1013,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template - __shared_ptr& + _Assignable<_Tp1*> operator=(__shared_ptr<_Tp1, _Lp>&& __r) noexcept { __shared_ptr(std::move(__r)).swap(*this); @@ -1017,7 +1021,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template - __shared_ptr& + _Assignable::pointer> operator=(std::unique_ptr<_Tp1, _Del>&& __r) { __shared_ptr(std::move(__r)).swap(*this); @@ -1029,7 +1033,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { __shared_ptr().swap(*this); } template - void + _Convertible<_Tp1*> reset(_Tp1* __p) // _Tp1 must be complete. { // Catch self-reset errors. @@ -1038,12 +1042,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template - void + _Convertible<_Tp1*> reset(_Tp1* __p, _Deleter __d) { __shared_ptr(__p, __d).swap(*this); } template - void + _Convertible<_Tp1*> reset(_Tp1* __p, _Deleter __d, _Alloc __a) { __shared_ptr(__p, __d, std::move(__a)).swap(*this); } diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/assign/sfinae.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/assign/sfinae.cc new file mode 100644 index 00000000000..d79af047ea9 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/assign/sfinae.cc @@ -0,0 +1,75 @@ +// 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 copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-do compile { target c++11 } } + +#include + +template +constexpr bool can_assign() +{ return std::is_assignable, From>::value; } + +struct Base { }; +struct Derived : Base { }; + +// Positive cases: + +static_assert( can_assign&>(), + "void* convertible to const void*"); +static_assert( can_assign&&>(), + "void* convertible to const void*"); +static_assert( can_assign>(), + "int* convertible to const int*"); +static_assert( can_assign>(), + "Derived* convertible to Base*"); +static_assert( can_assign>(), + "Derived* convertible to const Base*"); + +// Negative cases: + +static_assert( !can_assign&>(), + "void* not convertible to int*"); +static_assert( !can_assign&&>(), + "void* not convertible to int*"); + +static_assert( !can_assign&>(), + "const int* not convertible to int*"); +static_assert( !can_assign&&>(), + "const int* not convertible to int*"); + +static_assert( !can_assign&>(), + "long* not convertible to int*"); +static_assert( !can_assign&&>(), + "long* not convertible to int*"); + +static_assert( !can_assign&&>(), + "unique_ptr::pointer not convertible to int*"); + +static_assert( !can_assign&>(), + "Base* not convertible to Derived*"); +static_assert( !can_assign&&>(), + "Base* not convertible to Derived*"); +static_assert( !can_assign&&>(), + "unique_ptr::pointer not convertible to Derived*"); + +struct Deleter { + using pointer = void*; + void operator()(pointer) const { } +}; + +static_assert( !can_assign&&>(), + "unique_ptr::pointer not convertible to Derived*"); diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/assign/shared_ptr_neg.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/assign/shared_ptr_neg.cc index 751495a63db..96f07b5549c 100644 --- a/libstdc++-v3/testsuite/20_util/shared_ptr/assign/shared_ptr_neg.cc +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/assign/shared_ptr_neg.cc @@ -28,24 +28,10 @@ struct B { }; // 20.6.6.2.3 shared_ptr assignment [util.smartptr.shared.assign] // Assignment from incompatible shared_ptr -int +void test01() { - bool test __attribute__((unused)) = true; - std::shared_ptr a; std::shared_ptr b; - a = b; // { dg-error "here" } - - return 0; -} - -int -main() -{ - test01(); - return 0; + a = b; // { dg-error "no match" } } -// { dg-error "In instantiation" "" { target *-*-* } 0 } -// { dg-error "cannot convert" "" { target *-*-* } 0 } -// { dg-error "required from" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc index 530256a94bc..c58c8421a3f 100644 --- a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc @@ -32,8 +32,6 @@ void test01() { X* px = 0; std::shared_ptr p1(px); // { dg-error "here" } - // { dg-error "incomplete" "" { target *-*-* } 893 } - std::shared_ptr p9(ap()); // { dg-error "here" } - // { dg-error "incomplete" "" { target *-*-* } 307 } + // { dg-error "incomplete" "" { target *-*-* } 0 } } diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/void_neg.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/void_neg.cc index f77ddec9c7b..0cadf25bffb 100644 --- a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/void_neg.cc +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/void_neg.cc @@ -24,5 +24,5 @@ void test01() { std::shared_ptr p((void*)nullptr); // { dg-error "here" } - // { dg-error "incomplete" "" { target *-*-* } 892 } + // { dg-error "incomplete" "" { target *-*-* } 0 } } diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/modifiers/reset_sfinae.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/modifiers/reset_sfinae.cc new file mode 100644 index 00000000000..f75530f4247 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/modifiers/reset_sfinae.cc @@ -0,0 +1,92 @@ +// 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 copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-do compile { target c++11 } } + +#include + +template + struct resettable + : std::false_type + { }; + +template struct type_list { }; + +template + using reset_result + = decltype(std::shared_ptr{}.reset(std::declval()...)); + +template + struct resettable, reset_result> + : std::true_type + { }; + +template +constexpr bool can_reset() +{ return resettable>::value; } + +template +struct Deleter { + void operator()(T*) const; +}; + +template +using Alloc = std::allocator; + +struct Base { }; +struct Derived : Base { }; + +// Positive cases: + +static_assert( can_reset(), + "void* convertible to const void*"); +static_assert( can_reset(), + "int* convertible to const int*"); +static_assert( can_reset(), + "Derived* convertible to Base*"); +static_assert( can_reset(), + "Derived* convertible to const Base*"); + +// Negative cases: + +static_assert( !can_reset(), + "void* not convertible to int*"); +static_assert( !can_reset>(), + "void* not convertible to int*"); +static_assert( !can_reset, Alloc>(), + "void* not convertible to int*"); + +static_assert( !can_reset(), + "const int* not convertible to int*"); +static_assert( !can_reset>(), + "const int* not convertible to int*"); +static_assert( !can_reset, Alloc>(), + "const int* not convertible to int*"); + +static_assert( !can_reset(), + "long* not convertible to int*"); +static_assert( !can_reset>(), + "long* not convertible to int*"); +static_assert( !can_reset, Alloc>(), + "long* not convertible to int*"); + +static_assert( !can_reset(), + "Base* not convertible to Derived*"); +static_assert( !can_reset>(), + "Base* not convertible to Derived*"); +static_assert( !can_reset, Alloc>(), + "Base* not convertible to Derived*"); -- 2.30.2