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>
|
||||
|
||||
* 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.
|
||||
|
@ -93,8 +93,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
class shared_ptr : public __shared_ptr<_Tp>
|
||||
{
|
||||
template<typename _Ptr>
|
||||
using _Convertible
|
||||
= typename enable_if<is_convertible<_Ptr, _Tp*>::value>::type;
|
||||
using _Convertible = 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:
|
||||
|
||||
@ -276,7 +280,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
shared_ptr& operator=(const shared_ptr&) noexcept = default;
|
||||
|
||||
template<typename _Tp1>
|
||||
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<class _Tp1>
|
||||
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<typename _Tp1, typename _Del>
|
||||
shared_ptr&
|
||||
_Assignable<typename unique_ptr<_Tp1, _Del>::pointer>
|
||||
operator=(std::unique_ptr<_Tp1, _Del>&& __r)
|
||||
{
|
||||
this->__shared_ptr<_Tp>::operator=(std::move(__r));
|
||||
|
@ -873,6 +873,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
using _Convertible
|
||||
= 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:
|
||||
typedef _Tp element_type;
|
||||
|
||||
@ -983,7 +987,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
constexpr __shared_ptr(nullptr_t) noexcept : __shared_ptr() { }
|
||||
|
||||
template<typename _Tp1>
|
||||
__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<class _Tp1>
|
||||
__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<typename _Tp1, typename _Del>
|
||||
__shared_ptr&
|
||||
_Assignable<typename unique_ptr<_Tp1, _Del>::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<typename _Tp1>
|
||||
void
|
||||
_Convertible<_Tp1*>
|
||||
reset(_Tp1* __p) // _Tp1 must be complete.
|
||||
{
|
||||
// Catch self-reset errors.
|
||||
@ -1038,12 +1042,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
}
|
||||
|
||||
template<typename _Tp1, typename _Deleter>
|
||||
void
|
||||
_Convertible<_Tp1*>
|
||||
reset(_Tp1* __p, _Deleter __d)
|
||||
{ __shared_ptr(__p, __d).swap(*this); }
|
||||
|
||||
template<typename _Tp1, typename _Deleter, typename _Alloc>
|
||||
void
|
||||
_Convertible<_Tp1*>
|
||||
reset(_Tp1* __p, _Deleter __d, _Alloc __a)
|
||||
{ __shared_ptr(__p, __d, std::move(__a)).swap(*this); }
|
||||
|
||||
|
75
libstdc++-v3/testsuite/20_util/shared_ptr/assign/sfinae.cc
Normal file
75
libstdc++-v3/testsuite/20_util/shared_ptr/assign/sfinae.cc
Normal file
@ -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]
|
||||
|
||||
// Assignment from incompatible shared_ptr<Y>
|
||||
int
|
||||
void
|
||||
test01()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
|
||||
std::shared_ptr<A> a;
|
||||
std::shared_ptr<B> b;
|
||||
a = b; // { dg-error "here" }
|
||||
|
||||
return 0;
|
||||
a = b; // { dg-error "no match" }
|
||||
}
|
||||
|
||||
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;
|
||||
std::shared_ptr<X> p1(px); // { dg-error "here" }
|
||||
// { dg-error "incomplete" "" { target *-*-* } 893 }
|
||||
|
||||
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()
|
||||
{
|
||||
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
Block a user