mirror of git://gcc.gnu.org/git/gcc.git
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
This commit is contained in:
parent
e46d22a821
commit
7663cae227
|
|
@ -1,5 +1,26 @@
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
{ __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
|
||||||
}
|
}
|
||||||
|
|
||||||
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); }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
// <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 { };
|
||||||
// 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()
|
||||||
{
|
{
|
||||||
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 @@
|
||||||
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 }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
// <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*");
|
||||||
Loading…
Reference in New Issue