aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2016-08-31 17:57:20 +0100
committerJonathan Wakely <redi@gcc.gnu.org>2016-08-31 17:57:20 +0100
commit7663cae227b8337bbcf3355698b2aa43cb1a5f70 (patch)
treed67ccc26639c2c37194d284938a2c2d7da567bca
parente46d22a82119006ef69b4ba101565014ccaa9223 (diff)
downloadgcc-7663cae227b8337bbcf3355698b2aa43cb1a5f70.zip
gcc-7663cae227b8337bbcf3355698b2aa43cb1a5f70.tar.gz
gcc-7663cae227b8337bbcf3355698b2aa43cb1a5f70.tar.bz2
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
-rw-r--r--libstdc++-v3/ChangeLog21
-rw-r--r--libstdc++-v3/include/bits/shared_ptr.h14
-rw-r--r--libstdc++-v3/include/bits/shared_ptr_base.h16
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/assign/sfinae.cc75
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/assign/shared_ptr_neg.cc18
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc4
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/cons/void_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/modifiers/reset_sfinae.cc92
8 files changed, 211 insertions, 31 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index d608f6b..10761e8 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -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.
diff --git a/libstdc++-v3/include/bits/shared_ptr.h b/libstdc++-v3/include/bits/shared_ptr.h
index 747b09a..b2523b8 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<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));
diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h
index 60b825c..4ae2668 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<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); }
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 0000000..d79af04
--- /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
+// <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*");
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 751495a..96f07b5 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<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;
-}
-
-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 530256a..c58c842 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<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 }
}
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 f77ddec..0cadf25 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<void> 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 0000000..f75530f
--- /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
+// <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*");