diff options
author | ville <ville@138bc75d-0d04-0410-961f-82ee72b054a4> | 2015-08-08 11:07:34 +0000 |
---|---|---|
committer | ville <ville@138bc75d-0d04-0410-961f-82ee72b054a4> | 2015-08-08 11:07:34 +0000 |
commit | a3f807e8ae39635a7a4a0cde1ce90e76a5fd636e (patch) | |
tree | 97230bb560a8b0cb2868d38cf3d214654664119c /libstdc++-v3 | |
parent | 9f24c02944512a5b86c5bc6c3b4b23c43518397d (diff) | |
download | gcc-a3f807e8ae39635a7a4a0cde1ce90e76a5fd636e.tar.gz |
2015-08-08 Ville Voutilainen <ville.voutilainen@gmail.com>
Implement N4089 Safe conversions in unique_ptr<T[]> (LWG 2118)
and N4366 LWG 2228: Missing SFINAE rule in unique_ptr
templated assignment
* include/bits/unique_ptr.h
(__remove_cv, __is_derived_Tp): Remove.
(default_delete::default_delete(const default_delete<_Up[]>)):
Constrain with array convertibility.
(default_delete::operator(_Up*)): Turn into a template,
constrain with array convertibility.
(__safe_conversion_up): New, single object version.
(unique_ptr(unique_ptr<_Up, _Ep>&&)): Constrain with deleter
convertibility.
(unique_ptr::operator=(unique_ptr<_Up, _Ep>&&)): Likewise, and add
is_assignable as a constraint.
(__safe_conversion_up): Array version, renamed from __safe_conversion,
updated to implement N4089.
(__safe_conversion_raw): New.
(unique_ptr(_Up)): Turn into a template, constrain with array
convertibility.
(unique_ptr(_Up,
typename conditional<is_reference<deleter_type>::value,
deleter_type, const deleter_type&>::type)): Likewise.
(unique_ptr(_Up, typename
remove_reference<deleter_type>::type&&)): Likewise.
(unique_ptr(unique_ptr<_Up, _Ep>&&)): Likewise.
(operator=(unique_ptr<_Up, _Ep>&&)): Likewise, and add
is_assignable as a constraint (array version).
(reset(_Up)): Turn into a template, constrain with array
convertibility.
(reset(nullptr_t)): New.
* testsuite/20_util/default_delete/48631_neg.cc: Adjust.
* testsuite/20_util/unique_ptr/assign/48635.cc: Likewise.
* testsuite/20_util/unique_ptr/assign/48635_neg.cc: Likewise.
* testsuite/20_util/unique_ptr/assign/cv_qual.cc: Likewise.
* testsuite/20_util/unique_ptr/cons/cv_qual.cc: Likewise.
* testsuite/20_util/unique_ptr/dr2228.cc: New.
* testsuite/20_util/unique_ptr/modifiers/cv_qual.cc: Adjust.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@226733 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libstdc++-v3')
9 files changed, 233 insertions, 102 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 787a7a5768e..fc8b2b8a153 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,43 @@ +2015-08-08 Ville Voutilainen <ville.voutilainen@gmail.com> + + Implement N4089 Safe conversions in unique_ptr<T[]> (LWG 2118) + and N4366 LWG 2228: Missing SFINAE rule in unique_ptr + templated assignment + * include/bits/unique_ptr.h + (__remove_cv, __is_derived_Tp): Remove. + (default_delete::default_delete(const default_delete<_Up[]>)): + Constrain with array convertibility. + (default_delete::operator(_Up*)): Turn into a template, + constrain with array convertibility. + (__safe_conversion_up): New, single object version. + (unique_ptr(unique_ptr<_Up, _Ep>&&)): Constrain with deleter + convertibility. + (unique_ptr::operator=(unique_ptr<_Up, _Ep>&&)): Likewise, and add + is_assignable as a constraint. + (__safe_conversion_up): Array version, renamed from __safe_conversion, + updated to implement N4089. + (__safe_conversion_raw): New. + (unique_ptr(_Up)): Turn into a template, constrain with array + convertibility. + (unique_ptr(_Up, + typename conditional<is_reference<deleter_type>::value, + deleter_type, const deleter_type&>::type)): Likewise. + (unique_ptr(_Up, typename + remove_reference<deleter_type>::type&&)): Likewise. + (unique_ptr(unique_ptr<_Up, _Ep>&&)): Likewise. + (operator=(unique_ptr<_Up, _Ep>&&)): Likewise, and add + is_assignable as a constraint (array version). + (reset(_Up)): Turn into a template, constrain with array + convertibility. + (reset(nullptr_t)): New. + * testsuite/20_util/default_delete/48631_neg.cc: Adjust. + * testsuite/20_util/unique_ptr/assign/48635.cc: Likewise. + * testsuite/20_util/unique_ptr/assign/48635_neg.cc: Likewise. + * testsuite/20_util/unique_ptr/assign/cv_qual.cc: Likewise. + * testsuite/20_util/unique_ptr/cons/cv_qual.cc: Likewise. + * testsuite/20_util/unique_ptr/dr2228.cc: New. + * testsuite/20_util/unique_ptr/modifiers/cv_qual.cc: Adjust. + 2015-08-05 Nikolai Bozhenov <n.bozhenov@samsung.com> * testsuite/20_util/enable_shared_from_this/cons/constexpr.cc: Remove diff --git a/libstdc++-v3/include/bits/unique_ptr.h b/libstdc++-v3/include/bits/unique_ptr.h index 08ce01f7c7e..8ab55da75d3 100644 --- a/libstdc++-v3/include/bits/unique_ptr.h +++ b/libstdc++-v3/include/bits/unique_ptr.h @@ -83,16 +83,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp> struct default_delete<_Tp[]> { - private: - template<typename _Up> - using __remove_cv = typename remove_cv<_Up>::type; - - // Like is_base_of<_Tp, _Up> but false if unqualified types are the same - template<typename _Up> - using __is_derived_Tp - = __and_< is_base_of<_Tp, _Up>, - __not_<is_same<__remove_cv<_Tp>, __remove_cv<_Up>>> >; - public: /// Default constructor constexpr default_delete() noexcept = default; @@ -107,21 +97,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * pointer to the base type. */ template<typename _Up, typename = typename - enable_if<!__is_derived_Tp<_Up>::value>::type> + enable_if<is_convertible<_Up(*)[], _Tp(*)[]>::value>::type> default_delete(const default_delete<_Up[]>&) noexcept { } /// Calls @c delete[] @p __ptr - void - operator()(_Tp* __ptr) const + template<typename _Up> + typename enable_if<is_convertible<_Up(*)[], _Tp(*)[]>::value>::type + operator()(_Up* __ptr) const { static_assert(sizeof(_Tp)>0, "can't delete pointer to incomplete type"); delete [] __ptr; } - - template<typename _Up> - typename enable_if<__is_derived_Tp<_Up>::value>::type - operator()(_Up*) const = delete; }; /// 20.7.1.2 unique_ptr for single objects. @@ -151,6 +138,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typedef _Tp element_type; typedef _Dp deleter_type; + + // helper template for detecting a safe conversion from another + // unique_ptr + template<typename _Up, typename _Ep> + using __safe_conversion_up = __and_< + is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>, + __not_<is_array<_Up>>, + __or_<__and_<is_reference<deleter_type>, + is_same<deleter_type, _Ep>>, + __and_<__not_<is_reference<deleter_type>>, + is_convertible<_Ep, deleter_type>> + > + >; + // Constructors. /// Default constructor, creates a unique_ptr that owns nothing. @@ -212,8 +213,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * and @p __u has a compatible deleter type. */ template<typename _Up, typename _Ep, typename = _Require< - is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>, - __not_<is_array<_Up>>, + __safe_conversion_up<_Up, _Ep>, typename conditional<is_reference<_Dp>::value, is_same<_Ep, _Dp>, is_convertible<_Ep, _Dp>>::type>> @@ -261,11 +261,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * Invokes the deleter first if this object owns a pointer. */ template<typename _Up, typename _Ep> - typename enable_if< __and_< - is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>, - __not_<is_array<_Up>> - >::value, - unique_ptr&>::type + typename enable_if< __and_< + __safe_conversion_up<_Up, _Ep>, + is_assignable<deleter_type&, _Ep&&> + >::value, + unique_ptr&>::type operator=(unique_ptr<_Up, _Ep>&& __u) noexcept { reset(__u.release()); @@ -391,23 +391,41 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION = __and_< is_base_of<_Tp, _Up>, __not_<is_same<__remove_cv<_Tp>, __remove_cv<_Up>>> >; - template<typename _Up, typename _Ep, - typename _Tp_pointer = typename _Pointer::type, - typename _Up_pointer = typename unique_ptr<_Up, _Ep>::pointer> - using __safe_conversion = __and_< - is_convertible<_Up_pointer, _Tp_pointer>, - is_array<_Up>, - __or_<__not_<is_pointer<_Up_pointer>>, - __not_<is_pointer<_Tp_pointer>>, - __not_<__is_derived_Tp<typename remove_extent<_Up>::type>> - > - >; public: typedef typename _Pointer::type pointer; typedef _Tp element_type; typedef _Dp deleter_type; + // helper template for detecting a safe conversion from another + // unique_ptr + template<typename _Up, typename _Ep, + typename _Up_up = unique_ptr<_Up, _Ep>, + typename _Up_element_type = typename _Up_up::element_type> + using __safe_conversion_up = __and_< + is_array<_Up>, + is_same<pointer, element_type*>, + is_same<typename _Up_up::pointer, _Up_element_type*>, + is_convertible<_Up_element_type(*)[], element_type(*)[]>, + __or_<__and_<is_reference<deleter_type>, is_same<deleter_type, _Ep>>, + __and_<__not_<is_reference<deleter_type>>, + is_convertible<_Ep, deleter_type>>> + >; + + // helper template for detecting a safe conversion from a raw pointer + template<typename _Up> + using __safe_conversion_raw = __and_< + __or_<__or_<is_same<_Up, pointer>, + is_same<_Up, nullptr_t>>, + __and_<is_pointer<_Up>, + is_same<pointer, element_type*>, + is_convertible< + typename remove_pointer<_Up>::type(*)[], + element_type(*)[]> + > + > + >; + // Constructors. /// Default constructor, creates a unique_ptr that owns nothing. @@ -418,42 +436,48 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /** Takes ownership of a pointer. * - * @param __p A pointer to an array of @c element_type + * @param __p A pointer to an array of a type safely convertible + * to an array of @c element_type * * The deleter will be value-initialized. */ + template<typename _Up, + typename = typename enable_if< + __safe_conversion_raw<_Up>::value, bool>::type> explicit - unique_ptr(pointer __p) noexcept + unique_ptr(_Up __p) noexcept : _M_t(__p, deleter_type()) { static_assert(!is_pointer<deleter_type>::value, "constructed with null function pointer deleter"); } - // Disable construction from convertible pointer types. - template<typename _Up, typename = _Require<is_pointer<pointer>, - is_convertible<_Up*, pointer>, __is_derived_Tp<_Up>>> - explicit - unique_ptr(_Up* __p) = delete; - /** Takes ownership of a pointer. * - * @param __p A pointer to an array of @c element_type + * @param __p A pointer to an array of a type safely convertible + * to an array of @c element_type * @param __d A reference to a deleter. * * The deleter will be initialized with @p __d */ - unique_ptr(pointer __p, - typename conditional<is_reference<deleter_type>::value, - deleter_type, const deleter_type&>::type __d) noexcept + template<typename _Up, + typename = typename enable_if< + __safe_conversion_raw<_Up>::value, bool>::type> + unique_ptr(_Up __p, + typename conditional<is_reference<deleter_type>::value, + deleter_type, const deleter_type&>::type __d) noexcept : _M_t(__p, __d) { } /** Takes ownership of a pointer. * - * @param __p A pointer to an array of @c element_type + * @param __p A pointer to an array of a type safely convertible + * to an array of @c element_type * @param __d A reference to a deleter. * * The deleter will be initialized with @p std::move(__d) */ - unique_ptr(pointer __p, typename + template<typename _Up, + typename = typename enable_if< + __safe_conversion_raw<_Up>::value, bool>::type> + unique_ptr(_Up __p, typename remove_reference<deleter_type>::type&& __d) noexcept : _M_t(std::move(__p), std::move(__d)) { static_assert(!is_reference<deleter_type>::value, @@ -467,11 +491,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { } template<typename _Up, typename _Ep, - typename = _Require<__safe_conversion<_Up, _Ep>, - typename conditional<is_reference<_Dp>::value, - is_same<_Ep, _Dp>, - is_convertible<_Ep, _Dp>>::type - >> + typename = _Require<__safe_conversion_up<_Up, _Ep>>> unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter())) { } @@ -510,7 +530,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ template<typename _Up, typename _Ep> typename - enable_if<__safe_conversion<_Up, _Ep>::value, unique_ptr&>::type + enable_if<__and_<__safe_conversion_up<_Up, _Ep>, + is_assignable<deleter_type&, _Ep&&> + >::value, + unique_ptr&>::type operator=(unique_ptr<_Up, _Ep>&& __u) noexcept { reset(__u.release()); @@ -572,8 +595,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * * The deleter will be invoked if a pointer is already owned. */ + template <typename _Up, + typename = _Require< + __or_<is_same<_Up, pointer>, + __and_<is_same<pointer, element_type*>, + is_pointer<_Up>, + is_convertible< + typename remove_pointer<_Up>::type(*)[], + element_type(*)[] + > + > + > + >> void - reset(pointer __p = pointer()) noexcept + reset(_Up __p) noexcept { using std::swap; swap(std::get<0>(_M_t), __p); @@ -581,10 +616,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION get_deleter()(__p); } - // Disable resetting from convertible pointer types. - template<typename _Up, typename = _Require<is_pointer<pointer>, - is_convertible<_Up*, pointer>, __is_derived_Tp<_Up>>> - void reset(_Up*) = delete; + void reset(nullptr_t = nullptr) noexcept + { + reset(pointer()); + } /// Exchange the pointer and deleter with another object. void @@ -597,19 +632,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Disable copy from lvalue. unique_ptr(const unique_ptr&) = delete; unique_ptr& operator=(const unique_ptr&) = delete; - - // Disable construction from convertible pointer types. - template<typename _Up, typename = _Require<is_pointer<pointer>, - is_convertible<_Up*, pointer>, __is_derived_Tp<_Up>>> - unique_ptr(_Up*, typename - conditional<is_reference<deleter_type>::value, - deleter_type, const deleter_type&>::type) = delete; - - // Disable construction from convertible pointer types. - template<typename _Up, typename = _Require<is_pointer<pointer>, - is_convertible<_Up*, pointer>, __is_derived_Tp<_Up>>> - unique_ptr(_Up*, typename - remove_reference<deleter_type>::type&&) = delete; }; template<typename _Tp, typename _Dp> diff --git a/libstdc++-v3/testsuite/20_util/default_delete/48631_neg.cc b/libstdc++-v3/testsuite/20_util/default_delete/48631_neg.cc index aed2cf47da5..6ee12787271 100644 --- a/libstdc++-v3/testsuite/20_util/default_delete/48631_neg.cc +++ b/libstdc++-v3/testsuite/20_util/default_delete/48631_neg.cc @@ -26,6 +26,5 @@ struct D : B { }; // libstdc++/48631 D d; std::default_delete<B[]> db; -typedef decltype(db(&d)) type; // { dg-error "use of deleted function" } -// { dg-prune-output "declared" } -// { dg-prune-output "invalid" } +typedef decltype(db(&d)) type; // { dg-error "no match" } +// { dg-error "no type" "" { target *-*-* } 106 } diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/assign/48635.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/assign/48635.cc index 9014a32e606..37d6c36ecb1 100644 --- a/libstdc++-v3/testsuite/20_util/unique_ptr/assign/48635.cc +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/assign/48635.cc @@ -59,16 +59,8 @@ void test01() DDeleter dd; - std::unique_ptr<int, DDeleter&> p1t(nullptr, dd); - std::unique_ptr<int, Deleter&> p2t(nullptr, d); - p2t = std::move(p1t); - std::unique_ptr<int[], Deleter&> p1a(nullptr, d), p2a(nullptr, d); p2a = std::move(p1a); - - std::unique_ptr<int[], DDeleter&> p1at(nullptr, dd); - std::unique_ptr<int[], Deleter&> p2at(nullptr, d); - p2at = std::move(p1at); } int main() diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/assign/48635_neg.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/assign/48635_neg.cc index 185f39c093a..68be4c41e70 100644 --- a/libstdc++-v3/testsuite/20_util/unique_ptr/assign/48635_neg.cc +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/assign/48635_neg.cc @@ -24,7 +24,7 @@ struct D; struct B { - B& operator=(D&) = delete; // { dg-error "declared here" } + B& operator=(D&) = delete; template<class T> void operator()(T*) const {} @@ -39,12 +39,14 @@ void f() D d; std::unique_ptr<int, B&> ub(nullptr, b); + std::unique_ptr<int, B> ub2(nullptr, b); std::unique_ptr<int, D&> ud(nullptr, d); - ub = std::move(ud); -// { dg-error "use of deleted function" "" { target *-*-* } 272 } + ub = std::move(ud); // { dg-error "no match" } + ub2 = ud; // { dg-error "no match" } +// { dg-error "no type" "" { target *-*-* } 269 } std::unique_ptr<int[], B&> uba(nullptr, b); std::unique_ptr<int[], D&> uda(nullptr, d); - uba = std::move(uda); -// { dg-error "use of deleted function" "" { target *-*-* } 517 } + uba = std::move(uda); // { dg-error "no match" } +// { dg-error "no type" "" { target *-*-* } 537 } } diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/assign/cv_qual.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/assign/cv_qual.cc index 0938377806d..da73fccacec 100644 --- a/libstdc++-v3/testsuite/20_util/unique_ptr/assign/cv_qual.cc +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/assign/cv_qual.cc @@ -82,8 +82,10 @@ struct deleter void test04() { - // Allow conversions from user-defined pointer-like types + // Disallow conversions from incompatible deleter std::unique_ptr<B[], deleter<A_pointer>> p; std::unique_ptr<A[], deleter<A*>> upA; - upA = std::move(p); + upA = std::move(p); // { dg-error "no match" } + // { dg-error "no type" "" { target *-*-* } 537 } + // { dg-error "no matching function" "" { target *-*-* } 614 } } diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/cv_qual.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/cv_qual.cc index f7d160635ed..f399b7cb2a0 100644 --- a/libstdc++-v3/testsuite/20_util/unique_ptr/cons/cv_qual.cc +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/cons/cv_qual.cc @@ -88,11 +88,25 @@ void test07() { // Allow conversions from user-defined pointer-like types + // for the single-object version A_pointer p; - std::unique_ptr<A[]> upA(p); - std::unique_ptr<const A[]> cA(p); - std::unique_ptr<volatile A[]> vA(p); - std::unique_ptr<const volatile A[]> cvA(p); + std::unique_ptr<A> upA(p); + std::unique_ptr<const A> cA(p); + std::unique_ptr<volatile A> vA(p); + std::unique_ptr<const volatile A> cvA(p); + // Allow conversions from user-defined pointer-like types + // for the array version when the type is converted explicitly + std::unique_ptr<A[]> upA2((A*)p); + std::unique_ptr<const A[]> cA2((A*)p); + std::unique_ptr<volatile A[]> vA2((A*)p); + std::unique_ptr<const volatile A[]> cvA2((A*)p); + // Disallow conversions from user-defined pointer-like types + // for the array version + std::unique_ptr<A[]> upA3(p); // { dg-error "no matching function" } + std::unique_ptr<const A[]> cA3(p); // { dg-error "no matching function" } + std::unique_ptr<volatile A[]> vA3(p); // { dg-error "no matching function" } + std::unique_ptr<const volatile A[]> cvA3(p); // { dg-error "no matching function" } + // { dg-error "no type" "" { target *-*-* } 445 } } template<typename T> @@ -108,8 +122,8 @@ struct deleter void test08() { - // Allow conversions from user-defined pointer-like types + // Disallow conversions from non-assignable deleter std::unique_ptr<B[], deleter<A_pointer>> p; - std::unique_ptr<A[], deleter<A*>> upA(std::move(p)); + std::unique_ptr<A[], deleter<A*>> upA(std::move(p)); // { dg-error "no matching function" } } diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/dr2228.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/dr2228.cc new file mode 100644 index 00000000000..ae996daad2d --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/dr2228.cc @@ -0,0 +1,38 @@ +// { dg-options "-std=gnu++11" } +// { dg-do compile } + +// Copyright (C) 2015 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/>. + +#include <memory> +#include <type_traits> + +struct do_nothing +{ + template <class T> + void operator()(T*) {} +}; + +int +main() +{ + int i = 0; + std::unique_ptr<int, do_nothing> p1(&i); + std::unique_ptr<int> p2; + static_assert(!std::is_assignable<decltype(p2), decltype(p1)>::value, ""); + +} diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/cv_qual.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/cv_qual.cc index eaa7d43da39..4ae2f9de48b 100644 --- a/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/cv_qual.cc +++ b/libstdc++-v3/testsuite/20_util/unique_ptr/modifiers/cv_qual.cc @@ -66,14 +66,36 @@ struct A_pointer { operator A*() const { return nullptr; } }; void test07() { - // Allow conversions from user-defined pointer-like types A_pointer p; - std::unique_ptr<A[]> upA; + // Allow conversions from user-defined pointer-like types + // for the single-object version + std::unique_ptr<A> upA; upA.reset(p); - std::unique_ptr<const A[]> cA; + std::unique_ptr<const A> cA; cA.reset(p); - std::unique_ptr<volatile A[]> vA; + std::unique_ptr<volatile A> vA; vA.reset(p); - std::unique_ptr<const volatile A[]> cvA; + std::unique_ptr<const volatile A> cvA; cvA.reset(p); + // Allow conversions from user-defined pointer-like types + // for the array version when the type is converted explicitly + std::unique_ptr<A[]> upA2; + upA2.reset((A*)p); + std::unique_ptr<const A[]> cA2; + cA2.reset((A*)p); + std::unique_ptr<volatile A[]> vA2; + vA2.reset((A*)p); + std::unique_ptr<const volatile A[]> cvA2; + cvA2.reset((A*)p); + // Disallow conversions from user-defined pointer-like types + // for the array version + std::unique_ptr<A[]> upA3; + upA3.reset(p); // { dg-error "no matching function" } + std::unique_ptr<const A[]> cA3; + cA3.reset(p); // { dg-error "no matching function" } + std::unique_ptr<volatile A[]> vA3; + vA3.reset(p); // { dg-error "no matching function" } + std::unique_ptr<const volatile A[]> cvA3; + cvA3.reset(p); // { dg-error "no matching function" } + // { dg-error "no matching function" "" { target *-*-* } 614 } } |