Commit 7663cae2 by Jonathan Wakely Committed by Jonathan Wakely

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
parent e46d22a8
2016-08-31 Jonathan Wakely <jwakely@redhat.com> 2016-08-31 Jonathan Wakely <jwakely@redhat.com>
* 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 * include/bits/stl_tree.h (_Rb_tree::operator=(_Rb_tree&&)): Move
comparison object. comparison object.
* testsuite/23_containers/set/move_comparison.cc: New test. * testsuite/23_containers/set/move_comparison.cc: New test.
......
...@@ -93,8 +93,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -93,8 +93,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
class shared_ptr : public __shared_ptr<_Tp> class shared_ptr : public __shared_ptr<_Tp>
{ {
template<typename _Ptr> template<typename _Ptr>
using _Convertible using _Convertible = typename
= typename enable_if<is_convertible<_Ptr, _Tp*>::value>::type; enable_if<is_convertible<_Ptr, _Tp*>::value>::type;
template<typename _Ptr>
using _Assignable = typename
enable_if<is_convertible<_Ptr, _Tp*>::value, shared_ptr&>::type;
public: public:
...@@ -276,7 +280,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -276,7 +280,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
shared_ptr& operator=(const shared_ptr&) noexcept = default; shared_ptr& operator=(const shared_ptr&) noexcept = default;
template<typename _Tp1> template<typename _Tp1>
shared_ptr& _Assignable<_Tp1*>
operator=(const shared_ptr<_Tp1>& __r) noexcept operator=(const shared_ptr<_Tp1>& __r) noexcept
{ {
this->__shared_ptr<_Tp>::operator=(__r); this->__shared_ptr<_Tp>::operator=(__r);
...@@ -301,7 +305,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -301,7 +305,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
} }
template<class _Tp1> template<class _Tp1>
shared_ptr& _Assignable<_Tp1*>
operator=(shared_ptr<_Tp1>&& __r) noexcept operator=(shared_ptr<_Tp1>&& __r) noexcept
{ {
this->__shared_ptr<_Tp>::operator=(std::move(__r)); this->__shared_ptr<_Tp>::operator=(std::move(__r));
...@@ -309,7 +313,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -309,7 +313,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
} }
template<typename _Tp1, typename _Del> template<typename _Tp1, typename _Del>
shared_ptr& _Assignable<typename unique_ptr<_Tp1, _Del>::pointer>
operator=(std::unique_ptr<_Tp1, _Del>&& __r) operator=(std::unique_ptr<_Tp1, _Del>&& __r)
{ {
this->__shared_ptr<_Tp>::operator=(std::move(__r)); this->__shared_ptr<_Tp>::operator=(std::move(__r));
......
...@@ -873,6 +873,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -873,6 +873,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
using _Convertible using _Convertible
= typename enable_if<is_convertible<_Ptr, _Tp*>::value>::type; = typename enable_if<is_convertible<_Ptr, _Tp*>::value>::type;
template<typename _Ptr>
using _Assignable = typename
enable_if<is_convertible<_Ptr, _Tp*>::value, __shared_ptr&>::type;
public: public:
typedef _Tp element_type; typedef _Tp element_type;
...@@ -983,7 +987,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -983,7 +987,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr __shared_ptr(nullptr_t) noexcept : __shared_ptr() { } constexpr __shared_ptr(nullptr_t) noexcept : __shared_ptr() { }
template<typename _Tp1> template<typename _Tp1>
__shared_ptr& _Assignable<_Tp1*>
operator=(const __shared_ptr<_Tp1, _Lp>& __r) noexcept operator=(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
{ {
_M_ptr = __r._M_ptr; _M_ptr = __r._M_ptr;
...@@ -1009,7 +1013,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1009,7 +1013,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
} }
template<class _Tp1> template<class _Tp1>
__shared_ptr& _Assignable<_Tp1*>
operator=(__shared_ptr<_Tp1, _Lp>&& __r) noexcept operator=(__shared_ptr<_Tp1, _Lp>&& __r) noexcept
{ {
__shared_ptr(std::move(__r)).swap(*this); __shared_ptr(std::move(__r)).swap(*this);
...@@ -1017,7 +1021,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1017,7 +1021,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
} }
template<typename _Tp1, typename _Del> template<typename _Tp1, typename _Del>
__shared_ptr& _Assignable<typename unique_ptr<_Tp1, _Del>::pointer>
operator=(std::unique_ptr<_Tp1, _Del>&& __r) operator=(std::unique_ptr<_Tp1, _Del>&& __r)
{ {
__shared_ptr(std::move(__r)).swap(*this); __shared_ptr(std::move(__r)).swap(*this);
...@@ -1029,7 +1033,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1029,7 +1033,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ __shared_ptr().swap(*this); } { __shared_ptr().swap(*this); }
template<typename _Tp1> template<typename _Tp1>
void _Convertible<_Tp1*>
reset(_Tp1* __p) // _Tp1 must be complete. reset(_Tp1* __p) // _Tp1 must be complete.
{ {
// Catch self-reset errors. // Catch self-reset errors.
...@@ -1038,12 +1042,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1038,12 +1042,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
} }
template<typename _Tp1, typename _Deleter> template<typename _Tp1, typename _Deleter>
void _Convertible<_Tp1*>
reset(_Tp1* __p, _Deleter __d) reset(_Tp1* __p, _Deleter __d)
{ __shared_ptr(__p, __d).swap(*this); } { __shared_ptr(__p, __d).swap(*this); }
template<typename _Tp1, typename _Deleter, typename _Alloc> template<typename _Tp1, typename _Deleter, typename _Alloc>
void _Convertible<_Tp1*>
reset(_Tp1* __p, _Deleter __d, _Alloc __a) reset(_Tp1* __p, _Deleter __d, _Alloc __a)
{ __shared_ptr(__p, __d, std::move(__a)).swap(*this); } { __shared_ptr(__p, __d, std::move(__a)).swap(*this); }
......
// 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
// <http://www.gnu.org/licenses/>.
// { dg-do compile { target c++11 } }
#include <memory>
template<typename T, typename From>
constexpr bool can_assign()
{ return std::is_assignable<std::shared_ptr<T>, From>::value; }
struct Base { };
struct Derived : Base { };
// Positive cases:
static_assert( can_assign<const void, const std::shared_ptr<void>&>(),
"void* convertible to const void*");
static_assert( can_assign<const void, std::shared_ptr<void>&&>(),
"void* convertible to const void*");
static_assert( can_assign<const int, std::shared_ptr<int>>(),
"int* convertible to const int*");
static_assert( can_assign<Base, std::shared_ptr<Derived>>(),
"Derived* convertible to Base*");
static_assert( can_assign<const Base, std::shared_ptr<Derived>>(),
"Derived* convertible to const Base*");
// Negative cases:
static_assert( !can_assign<int, const std::shared_ptr<void>&>(),
"void* not convertible to int*");
static_assert( !can_assign<int, std::shared_ptr<void>&&>(),
"void* not convertible to int*");
static_assert( !can_assign<int, const std::shared_ptr<const int>&>(),
"const int* not convertible to int*");
static_assert( !can_assign<int, std::shared_ptr<const int>&&>(),
"const int* not convertible to int*");
static_assert( !can_assign<int, const std::shared_ptr<long>&>(),
"long* not convertible to int*");
static_assert( !can_assign<int, std::shared_ptr<long>&&>(),
"long* not convertible to int*");
static_assert( !can_assign<int, std::unique_ptr<long>&&>(),
"unique_ptr<long>::pointer not convertible to int*");
static_assert( !can_assign<Derived, const std::shared_ptr<Base>&>(),
"Base* not convertible to Derived*");
static_assert( !can_assign<int, std::shared_ptr<long>&&>(),
"Base* not convertible to Derived*");
static_assert( !can_assign<Derived, std::unique_ptr<Base>&&>(),
"unique_ptr<Base>::pointer not convertible to Derived*");
struct Deleter {
using pointer = void*;
void operator()(pointer) const { }
};
static_assert( !can_assign<Derived, std::unique_ptr<Derived, Deleter>&&>(),
"unique_ptr<Derived, Deleter>::pointer not convertible to Derived*");
...@@ -28,24 +28,10 @@ struct B { }; ...@@ -28,24 +28,10 @@ struct B { };
// 20.6.6.2.3 shared_ptr assignment [util.smartptr.shared.assign] // 20.6.6.2.3 shared_ptr assignment [util.smartptr.shared.assign]
// Assignment from incompatible shared_ptr<Y> // Assignment from incompatible shared_ptr<Y>
int void
test01() test01()
{ {
bool test __attribute__((unused)) = true;
std::shared_ptr<A> a; std::shared_ptr<A> a;
std::shared_ptr<B> b; std::shared_ptr<B> b;
a = b; // { dg-error "here" } a = b; // { dg-error "no match" }
return 0;
}
int
main()
{
test01();
return 0;
} }
// { dg-error "In instantiation" "" { target *-*-* } 0 }
// { dg-error "cannot convert" "" { target *-*-* } 0 }
// { dg-error "required from" "" { target *-*-* } 0 }
...@@ -32,8 +32,6 @@ void test01() ...@@ -32,8 +32,6 @@ void test01()
{ {
X* px = 0; X* px = 0;
std::shared_ptr<X> p1(px); // { dg-error "here" } std::shared_ptr<X> p1(px); // { dg-error "here" }
// { dg-error "incomplete" "" { target *-*-* } 893 }
std::shared_ptr<X> p9(ap()); // { dg-error "here" } std::shared_ptr<X> p9(ap()); // { dg-error "here" }
// { dg-error "incomplete" "" { target *-*-* } 307 } // { dg-error "incomplete" "" { target *-*-* } 0 }
} }
...@@ -24,5 +24,5 @@ ...@@ -24,5 +24,5 @@
void test01() void test01()
{ {
std::shared_ptr<void> p((void*)nullptr); // { dg-error "here" } std::shared_ptr<void> p((void*)nullptr); // { dg-error "here" }
// { dg-error "incomplete" "" { target *-*-* } 892 } // { dg-error "incomplete" "" { target *-*-* } 0 }
} }
// 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
// <http://www.gnu.org/licenses/>.
// { dg-do compile { target c++11 } }
#include <memory>
template<typename T, typename Args, typename = void>
struct resettable
: std::false_type
{ };
template<typename... T> struct type_list { };
template<typename T, typename... Args>
using reset_result
= decltype(std::shared_ptr<T>{}.reset(std::declval<Args>()...));
template<typename T, typename... Args>
struct resettable<T, type_list<Args...>, reset_result<T, Args...>>
: std::true_type
{ };
template<typename T, typename... Args>
constexpr bool can_reset()
{ return resettable<T, type_list<Args...>>::value; }
template<typename T>
struct Deleter {
void operator()(T*) const;
};
template<typename T>
using Alloc = std::allocator<T>;
struct Base { };
struct Derived : Base { };
// Positive cases:
static_assert( can_reset<const void, void*>(),
"void* convertible to const void*");
static_assert( can_reset<const int, int*>(),
"int* convertible to const int*");
static_assert( can_reset<Base, Derived*>(),
"Derived* convertible to Base*");
static_assert( can_reset<const Base, Derived*>(),
"Derived* convertible to const Base*");
// Negative cases:
static_assert( !can_reset<int, void*>(),
"void* not convertible to int*");
static_assert( !can_reset<int, void*, Deleter<int>>(),
"void* not convertible to int*");
static_assert( !can_reset<int, void*, Deleter<int>, Alloc<int>>(),
"void* not convertible to int*");
static_assert( !can_reset<int, const int*>(),
"const int* not convertible to int*");
static_assert( !can_reset<int, const int*, Deleter<int>>(),
"const int* not convertible to int*");
static_assert( !can_reset<int, const int*, Deleter<int>, Alloc<int>>(),
"const int* not convertible to int*");
static_assert( !can_reset<int, long*>(),
"long* not convertible to int*");
static_assert( !can_reset<int, long*, Deleter<int>>(),
"long* not convertible to int*");
static_assert( !can_reset<int, long*, Deleter<int>, Alloc<int>>(),
"long* not convertible to int*");
static_assert( !can_reset<Derived, Base*>(),
"Base* not convertible to Derived*");
static_assert( !can_reset<Derived, Base*, Deleter<int>>(),
"Base* not convertible to Derived*");
static_assert( !can_reset<Derived, Base*, Deleter<int>, Alloc<int>>(),
"Base* not convertible to Derived*");
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment