1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// UNSUPPORTED: c++03
10
11// <memory>
12
13// unique_ptr
14
15// Test unique_ptr converting move ctor
16
17#include <memory>
18#include <cassert>
19
20#include "test_macros.h"
21#include "type_id.h"
22#include "unique_ptr_test_helper.h"
23
24template <int ID = 0>
25struct GenericDeleter {
26 TEST_CONSTEXPR_CXX23 void operator()(void*) const {}
27};
28
29template <int ID = 0>
30struct GenericConvertingDeleter {
31 template <int OID>
32 TEST_CONSTEXPR_CXX23 GenericConvertingDeleter(GenericConvertingDeleter<OID>) {}
33 TEST_CONSTEXPR_CXX23 void operator()(void*) const {}
34};
35
36template <class Templ, class Other>
37struct is_specialization;
38
39template <template <int> class Templ, int ID1, class Other>
40struct is_specialization<Templ<ID1>, Other> : std::false_type {};
41
42template <template <int> class Templ, int ID1, int ID2>
43struct is_specialization<Templ<ID1>, Templ<ID2> > : std::true_type {};
44
45template <class Templ, class Other>
46using EnableIfSpecialization = typename std::enable_if<
47 is_specialization<Templ, typename std::decay<Other>::type >::value
48 >::type;
49
50
51template <int ID>
52struct TrackingDeleter {
53 TEST_CONSTEXPR_CXX23 TrackingDeleter() : arg_type(&makeArgumentID<>()) {}
54
55 TEST_CONSTEXPR_CXX23 TrackingDeleter(TrackingDeleter const&) : arg_type(&makeArgumentID<TrackingDeleter const&>()) {}
56
57 TEST_CONSTEXPR_CXX23 TrackingDeleter(TrackingDeleter&&) : arg_type(&makeArgumentID<TrackingDeleter&&>()) {}
58
59 template <class T, class = EnableIfSpecialization<TrackingDeleter, T> >
60 TEST_CONSTEXPR_CXX23 TrackingDeleter(T&&) : arg_type(&makeArgumentID<T&&>()) {}
61
62 TEST_CONSTEXPR_CXX23 TrackingDeleter& operator=(TrackingDeleter const&) {
63 arg_type = &makeArgumentID<TrackingDeleter const&>();
64 return *this;
65 }
66
67 TEST_CONSTEXPR_CXX23 TrackingDeleter& operator=(TrackingDeleter&&) {
68 arg_type = &makeArgumentID<TrackingDeleter &&>();
69 return *this;
70 }
71
72 template <class T, class = EnableIfSpecialization<TrackingDeleter, T> >
73 TEST_CONSTEXPR_CXX23 TrackingDeleter& operator=(T&&) {
74 arg_type = &makeArgumentID<T&&>();
75 return *this;
76 }
77
78 TEST_CONSTEXPR_CXX23 void operator()(void*) const {}
79
80public:
81 TEST_CONSTEXPR_CXX23 TypeID const* reset() const {
82 TypeID const* tmp = arg_type;
83 arg_type = nullptr;
84 return tmp;
85 }
86
87 mutable TypeID const* arg_type;
88};
89
90
91template <class ExpectT, int ID>
92bool checkArg(TrackingDeleter<ID> const& d) {
93 return d.arg_type && *d.arg_type == makeArgumentID<ExpectT>();
94}
95
96template <bool IsArray>
97TEST_CONSTEXPR_CXX23 void test_sfinae() {
98 typedef typename std::conditional<IsArray, A[], A>::type VT;
99
100 { // Test that different non-reference deleter types are allowed so long
101 // as they convert to each other.
102 using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> >;
103 using U2 = std::unique_ptr<VT, GenericConvertingDeleter<1> >;
104 static_assert(std::is_constructible<U1, U2&&>::value, "");
105 }
106 { // Test that different non-reference deleter types are disallowed when
107 // they cannot convert.
108 using U1 = std::unique_ptr<VT, GenericDeleter<0> >;
109 using U2 = std::unique_ptr<VT, GenericDeleter<1> >;
110 static_assert(!std::is_constructible<U1, U2&&>::value, "");
111 }
112 { // Test that if the destination deleter is a reference type then only
113 // exact matches are allowed.
114 using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> const& >;
115 using U2 = std::unique_ptr<VT, GenericConvertingDeleter<0> >;
116 using U3 = std::unique_ptr<VT, GenericConvertingDeleter<0> &>;
117 using U4 = std::unique_ptr<VT, GenericConvertingDeleter<1> >;
118 using U5 = std::unique_ptr<VT, GenericConvertingDeleter<1> const&>;
119 static_assert(!std::is_constructible<U1, U2&&>::value, "");
120 static_assert(!std::is_constructible<U1, U3&&>::value, "");
121 static_assert(!std::is_constructible<U1, U4&&>::value, "");
122 static_assert(!std::is_constructible<U1, U5&&>::value, "");
123
124 using U1C = std::unique_ptr<const VT, GenericConvertingDeleter<0> const&>;
125 static_assert(std::is_nothrow_constructible<U1C, U1&&>::value, "");
126 }
127 { // Test that non-reference destination deleters can be constructed
128 // from any source deleter type with a suitable conversion. Including
129 // reference types.
130 using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> >;
131 using U2 = std::unique_ptr<VT, GenericConvertingDeleter<0> &>;
132 using U3 = std::unique_ptr<VT, GenericConvertingDeleter<0> const &>;
133 using U4 = std::unique_ptr<VT, GenericConvertingDeleter<1> >;
134 using U5 = std::unique_ptr<VT, GenericConvertingDeleter<1> &>;
135 using U6 = std::unique_ptr<VT, GenericConvertingDeleter<1> const&>;
136 static_assert(std::is_constructible<U1, U2&&>::value, "");
137 static_assert(std::is_constructible<U1, U3&&>::value, "");
138 static_assert(std::is_constructible<U1, U4&&>::value, "");
139 static_assert(std::is_constructible<U1, U5&&>::value, "");
140 static_assert(std::is_constructible<U1, U6&&>::value, "");
141 }
142}
143
144template <bool IsArray>
145TEST_CONSTEXPR_CXX23 void test_noexcept() {
146 typedef typename std::conditional<IsArray, A[], A>::type VT;
147 {
148 typedef std::unique_ptr<const VT> APtr;
149 typedef std::unique_ptr<VT> BPtr;
150 static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, "");
151 }
152 {
153 typedef std::unique_ptr<const VT, CDeleter<const VT> > APtr;
154 typedef std::unique_ptr<VT, CDeleter<VT> > BPtr;
155 static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, "");
156 }
157 {
158 typedef std::unique_ptr<const VT, NCDeleter<const VT>&> APtr;
159 typedef std::unique_ptr<VT, NCDeleter<const VT>&> BPtr;
160 static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, "");
161 }
162 {
163 typedef std::unique_ptr<const VT, const NCConstDeleter<const VT>&> APtr;
164 typedef std::unique_ptr<VT, const NCConstDeleter<const VT>&> BPtr;
165 static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, "");
166 }
167}
168
169template <bool IsArray>
170TEST_CONSTEXPR_CXX23 void test_deleter_value_category() {
171 typedef typename std::conditional<IsArray, A[], A>::type VT;
172 using TD1 = TrackingDeleter<1>;
173 using TD2 = TrackingDeleter<2>;
174 TD1 d1;
175 TD2 d2;
176
177 { // Test non-reference deleter conversions
178 using U1 = std::unique_ptr<VT, TD1 >;
179 using U2 = std::unique_ptr<VT, TD2 >;
180 U2 u2;
181 u2.get_deleter().reset();
182 U1 u1(std::move(u2));
183 assert(checkArg<TD2&&>(u1.get_deleter()));
184 }
185 { // Test assignment from non-const ref
186 using U1 = std::unique_ptr<VT, TD1 >;
187 using U2 = std::unique_ptr<VT, TD2& >;
188 U2 u2(nullptr, d2);
189 U1 u1(std::move(u2));
190 assert(checkArg<TD2&>(u1.get_deleter()));
191 }
192 { // Test assignment from const ref
193 using U1 = std::unique_ptr<VT, TD1 >;
194 using U2 = std::unique_ptr<VT, TD2 const& >;
195 U2 u2(nullptr, d2);
196 U1 u1(std::move(u2));
197 assert(checkArg<TD2 const&>(u1.get_deleter()));
198 }
199}
200
201TEST_CONSTEXPR_CXX23 bool test() {
202 {
203 test_sfinae</*IsArray*/false>();
204 test_noexcept<false>();
205 if (!TEST_IS_CONSTANT_EVALUATED)
206 test_deleter_value_category<false>();
207 }
208 {
209 test_sfinae</*IsArray*/true>();
210 test_noexcept<true>();
211 if (!TEST_IS_CONSTANT_EVALUATED)
212 test_deleter_value_category<true>();
213 }
214
215 return true;
216}
217
218int main(int, char**) {
219 test();
220#if TEST_STD_VER >= 23
221 static_assert(test());
222#endif
223
224 return 0;
225}
226

source code of libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.pass.cpp