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 "unique_ptr_test_helper.h"
22 #include "type_id.h"
23
24 template <int ID = 0>
25 struct GenericDeleter {
operator ()GenericDeleter26 void operator()(void*) const {}
27 };
28
29 template <int ID = 0>
30 struct GenericConvertingDeleter {
31
32 template <int OID>
GenericConvertingDeleterGenericConvertingDeleter33 GenericConvertingDeleter(GenericConvertingDeleter<OID>) {}
34
35 template <int OID>
operator =GenericConvertingDeleter36 GenericConvertingDeleter& operator=(GenericConvertingDeleter<OID> const&) {
37 return *this;
38 }
39
operator ()GenericConvertingDeleter40 void operator()(void*) const {}
41 };
42
43 template <class T, class U>
44 using EnableIfNotSame = typename std::enable_if<
45 !std::is_same<typename std::decay<T>::type, typename std::decay<U>::type>::value
46 >::type;
47
48 template <class Templ, class Other>
49 struct is_specialization;
50
51 template <template <int> class Templ, int ID1, class Other>
52 struct is_specialization<Templ<ID1>, Other> : std::false_type {};
53
54 template <template <int> class Templ, int ID1, int ID2>
55 struct is_specialization<Templ<ID1>, Templ<ID2> > : std::true_type {};
56
57 template <class Templ, class Other>
58 using EnableIfSpecialization = typename std::enable_if<
59 is_specialization<Templ, typename std::decay<Other>::type >::value
60 >::type;
61
62 template <int ID> struct TrackingDeleter;
63 template <int ID> struct ConstTrackingDeleter;
64
65 template <int ID>
66 struct TrackingDeleter {
TrackingDeleterTrackingDeleter67 TrackingDeleter() : arg_type(&makeArgumentID<>()) {}
68
TrackingDeleterTrackingDeleter69 TrackingDeleter(TrackingDeleter const&)
70 : arg_type(&makeArgumentID<TrackingDeleter const&>()) {}
71
TrackingDeleterTrackingDeleter72 TrackingDeleter(TrackingDeleter&&)
73 : arg_type(&makeArgumentID<TrackingDeleter &&>()) {}
74
75 template <class T, class = EnableIfSpecialization<TrackingDeleter, T> >
TrackingDeleterTrackingDeleter76 TrackingDeleter(T&&) : arg_type(&makeArgumentID<T&&>()) {}
77
operator =TrackingDeleter78 TrackingDeleter& operator=(TrackingDeleter const&) {
79 arg_type = &makeArgumentID<TrackingDeleter const&>();
80 return *this;
81 }
82
operator =TrackingDeleter83 TrackingDeleter& operator=(TrackingDeleter &&) {
84 arg_type = &makeArgumentID<TrackingDeleter &&>();
85 return *this;
86 }
87
88 template <class T, class = EnableIfSpecialization<TrackingDeleter, T> >
operator =TrackingDeleter89 TrackingDeleter& operator=(T&&) {
90 arg_type = &makeArgumentID<T&&>();
91 return *this;
92 }
93
operator ()TrackingDeleter94 void operator()(void*) const {}
95
96 public:
resetTrackingDeleter97 TypeID const* reset() const {
98 TypeID const* tmp = arg_type;
99 arg_type = nullptr;
100 return tmp;
101 }
102
103 mutable TypeID const* arg_type;
104 };
105
106 template <int ID>
107 struct ConstTrackingDeleter {
ConstTrackingDeleterConstTrackingDeleter108 ConstTrackingDeleter() : arg_type(&makeArgumentID<>()) {}
109
ConstTrackingDeleterConstTrackingDeleter110 ConstTrackingDeleter(ConstTrackingDeleter const&)
111 : arg_type(&makeArgumentID<ConstTrackingDeleter const&>()) {}
112
ConstTrackingDeleterConstTrackingDeleter113 ConstTrackingDeleter(ConstTrackingDeleter&&)
114 : arg_type(&makeArgumentID<ConstTrackingDeleter &&>()) {}
115
116 template <class T, class = EnableIfSpecialization<ConstTrackingDeleter, T> >
ConstTrackingDeleterConstTrackingDeleter117 ConstTrackingDeleter(T&&) : arg_type(&makeArgumentID<T&&>()) {}
118
operator =ConstTrackingDeleter119 const ConstTrackingDeleter& operator=(ConstTrackingDeleter const&) const {
120 arg_type = &makeArgumentID<ConstTrackingDeleter const&>();
121 return *this;
122 }
123
operator =ConstTrackingDeleter124 const ConstTrackingDeleter& operator=(ConstTrackingDeleter &&) const {
125 arg_type = &makeArgumentID<ConstTrackingDeleter &&>();
126 return *this;
127 }
128
129 template <class T, class = EnableIfSpecialization<ConstTrackingDeleter, T> >
operator =ConstTrackingDeleter130 const ConstTrackingDeleter& operator=(T&&) const {
131 arg_type = &makeArgumentID<T&&>();
132 return *this;
133 }
134
operator ()ConstTrackingDeleter135 void operator()(void*) const {}
136
137 public:
resetConstTrackingDeleter138 TypeID const* reset() const {
139 TypeID const* tmp = arg_type;
140 arg_type = nullptr;
141 return tmp;
142 }
143
144 mutable TypeID const* arg_type;
145 };
146
147 template <class ExpectT, int ID>
checkArg(TrackingDeleter<ID> const & d)148 bool checkArg(TrackingDeleter<ID> const& d) {
149 return d.arg_type && *d.arg_type == makeArgumentID<ExpectT>();
150 }
151
152 template <class ExpectT, int ID>
checkArg(ConstTrackingDeleter<ID> const & d)153 bool checkArg(ConstTrackingDeleter<ID> const& d) {
154 return d.arg_type && *d.arg_type == makeArgumentID<ExpectT>();
155 }
156
157 template <class From, bool AssignIsConst = false>
158 struct AssignDeleter {
159 AssignDeleter() = default;
160 AssignDeleter(AssignDeleter const&) = default;
161 AssignDeleter(AssignDeleter&&) = default;
162
163 AssignDeleter& operator=(AssignDeleter const&) = delete;
164 AssignDeleter& operator=(AssignDeleter &&) = delete;
165
166 template <class T> AssignDeleter& operator=(T&&) && = delete;
167 template <class T> AssignDeleter& operator=(T&&) const && = delete;
168
169 template <class T, class = typename std::enable_if<
170 std::is_same<T&&, From>::value && !AssignIsConst
171 >::type>
operator =AssignDeleter172 AssignDeleter& operator=(T&&) & { return *this; }
173
174 template <class T, class = typename std::enable_if<
175 std::is_same<T&&, From>::value && AssignIsConst
176 >::type>
operator =AssignDeleter177 const AssignDeleter& operator=(T&&) const & { return *this; }
178
179 template <class T>
operator ()AssignDeleter180 void operator()(T) const {}
181 };
182
183 template <class VT, class DDest, class DSource>
doDeleterTest()184 void doDeleterTest() {
185 using U1 = std::unique_ptr<VT, DDest>;
186 using U2 = std::unique_ptr<VT, DSource>;
187 static_assert(std::is_nothrow_assignable<U1, U2&&>::value, "");
188 typename std::decay<DDest>::type ddest;
189 typename std::decay<DSource>::type dsource;
190 U1 u1(nullptr, ddest);
191 U2 u2(nullptr, dsource);
192 u1 = std::move(u2);
193 }
194
195 template <bool IsArray>
test_sfinae()196 void test_sfinae() {
197 typedef typename std::conditional<IsArray, A[], A>::type VT;
198
199 { // Test that different non-reference deleter types are allowed so long
200 // as they convert to each other.
201 using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> >;
202 using U2 = std::unique_ptr<VT, GenericConvertingDeleter<1> >;
203 static_assert(std::is_assignable<U1, U2&&>::value, "");
204 }
205 { // Test that different non-reference deleter types are disallowed when
206 // they cannot convert.
207 using U1 = std::unique_ptr<VT, GenericDeleter<0> >;
208 using U2 = std::unique_ptr<VT, GenericDeleter<1> >;
209 static_assert(!std::is_assignable<U1, U2&&>::value, "");
210 }
211 { // Test that if the deleter assignment is not valid the assignment operator
212 // SFINAEs.
213 using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> const& >;
214 using U2 = std::unique_ptr<VT, GenericConvertingDeleter<0> >;
215 using U3 = std::unique_ptr<VT, GenericConvertingDeleter<0> &>;
216 using U4 = std::unique_ptr<VT, GenericConvertingDeleter<1> >;
217 using U5 = std::unique_ptr<VT, GenericConvertingDeleter<1> const&>;
218 static_assert(!std::is_assignable<U1, U2&&>::value, "");
219 static_assert(!std::is_assignable<U1, U3&&>::value, "");
220 static_assert(!std::is_assignable<U1, U4&&>::value, "");
221 static_assert(!std::is_assignable<U1, U5&&>::value, "");
222
223 using U1C = std::unique_ptr<const VT, GenericConvertingDeleter<0> const&>;
224 static_assert(std::is_nothrow_assignable<U1C, U1&&>::value, "");
225 }
226 { // Test that if the deleter assignment is not valid the assignment operator
227 // SFINAEs.
228 using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> & >;
229 using U2 = std::unique_ptr<VT, GenericConvertingDeleter<0> >;
230 using U3 = std::unique_ptr<VT, GenericConvertingDeleter<0> &>;
231 using U4 = std::unique_ptr<VT, GenericConvertingDeleter<1> >;
232 using U5 = std::unique_ptr<VT, GenericConvertingDeleter<1> const&>;
233
234 static_assert(std::is_nothrow_assignable<U1, U2&&>::value, "");
235 static_assert(std::is_nothrow_assignable<U1, U3&&>::value, "");
236 static_assert(std::is_nothrow_assignable<U1, U4&&>::value, "");
237 static_assert(std::is_nothrow_assignable<U1, U5&&>::value, "");
238
239 using U1C = std::unique_ptr<const VT, GenericConvertingDeleter<0> &>;
240 static_assert(std::is_nothrow_assignable<U1C, U1&&>::value, "");
241 }
242 { // Test that non-reference destination deleters can be assigned
243 // from any source deleter type with a suitable conversion. Including
244 // reference types.
245 using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> >;
246 using U2 = std::unique_ptr<VT, GenericConvertingDeleter<0> &>;
247 using U3 = std::unique_ptr<VT, GenericConvertingDeleter<0> const &>;
248 using U4 = std::unique_ptr<VT, GenericConvertingDeleter<1> >;
249 using U5 = std::unique_ptr<VT, GenericConvertingDeleter<1> &>;
250 using U6 = std::unique_ptr<VT, GenericConvertingDeleter<1> const&>;
251 static_assert(std::is_assignable<U1, U2&&>::value, "");
252 static_assert(std::is_assignable<U1, U3&&>::value, "");
253 static_assert(std::is_assignable<U1, U4&&>::value, "");
254 static_assert(std::is_assignable<U1, U5&&>::value, "");
255 static_assert(std::is_assignable<U1, U6&&>::value, "");
256 }
257 /////////////////////////////////////////////////////////////////////////////
258 {
259 using Del = GenericDeleter<0>;
260 using AD = AssignDeleter<Del&&>;
261 using ADC = AssignDeleter<Del&&, /*AllowConstAssign*/true>;
262 doDeleterTest<VT, AD, Del>();
263 doDeleterTest<VT, AD&, Del>();
264 doDeleterTest<VT, ADC const&, Del>();
265 }
266 {
267 using Del = GenericDeleter<0>;
268 using AD = AssignDeleter<Del&>;
269 using ADC = AssignDeleter<Del&, /*AllowConstAssign*/true>;
270 doDeleterTest<VT, AD, Del&>();
271 doDeleterTest<VT, AD&, Del&>();
272 doDeleterTest<VT, ADC const&, Del&>();
273 }
274 {
275 using Del = GenericDeleter<0>;
276 using AD = AssignDeleter<Del const&>;
277 using ADC = AssignDeleter<Del const&, /*AllowConstAssign*/true>;
278 doDeleterTest<VT, AD, Del const&>();
279 doDeleterTest<VT, AD&, Del const&>();
280 doDeleterTest<VT, ADC const&, Del const&>();
281 }
282 }
283
284
285 template <bool IsArray>
test_noexcept()286 void test_noexcept() {
287 typedef typename std::conditional<IsArray, A[], A>::type VT;
288 {
289 typedef std::unique_ptr<const VT> APtr;
290 typedef std::unique_ptr<VT> BPtr;
291 static_assert(std::is_nothrow_assignable<APtr, BPtr>::value, "");
292 }
293 {
294 typedef std::unique_ptr<const VT, CDeleter<const VT> > APtr;
295 typedef std::unique_ptr<VT, CDeleter<VT> > BPtr;
296 static_assert(std::is_nothrow_assignable<APtr, BPtr>::value, "");
297 }
298 {
299 typedef std::unique_ptr<const VT, NCDeleter<const VT>&> APtr;
300 typedef std::unique_ptr<VT, NCDeleter<const VT>&> BPtr;
301 static_assert(std::is_nothrow_assignable<APtr, BPtr>::value, "");
302 }
303 {
304 typedef std::unique_ptr<const VT, const NCConstDeleter<const VT>&> APtr;
305 typedef std::unique_ptr<VT, const NCConstDeleter<const VT>&> BPtr;
306 static_assert(std::is_nothrow_assignable<APtr, BPtr>::value, "");
307 }
308 }
309
310 template <bool IsArray>
test_deleter_value_category()311 void test_deleter_value_category() {
312 typedef typename std::conditional<IsArray, A[], A>::type VT;
313 using TD1 = TrackingDeleter<1>;
314 using TD2 = TrackingDeleter<2>;
315 TD1 d1;
316 TD2 d2;
317 using CD1 = ConstTrackingDeleter<1>;
318 using CD2 = ConstTrackingDeleter<2>;
319 CD1 cd1;
320 CD2 cd2;
321
322 { // Test non-reference deleter conversions
323 using U1 = std::unique_ptr<VT, TD1 >;
324 using U2 = std::unique_ptr<VT, TD2 >;
325 U1 u1;
326 U2 u2;
327 u1.get_deleter().reset();
328 u1 = std::move(u2);
329 assert(checkArg<TD2&&>(u1.get_deleter()));
330 }
331 { // Test assignment to non-const ref
332 using U1 = std::unique_ptr<VT, TD1& >;
333 using U2 = std::unique_ptr<VT, TD2 >;
334 U1 u1(nullptr, d1);
335 U2 u2;
336 u1.get_deleter().reset();
337 u1 = std::move(u2);
338 assert(checkArg<TD2&&>(u1.get_deleter()));
339 }
340 { // Test assignment to const&.
341 using U1 = std::unique_ptr<VT, CD1 const& >;
342 using U2 = std::unique_ptr<VT, CD2 >;
343 U1 u1(nullptr, cd1);
344 U2 u2;
345 u1.get_deleter().reset();
346 u1 = std::move(u2);
347 assert(checkArg<CD2&&>(u1.get_deleter()));
348 }
349
350 { // Test assignment from non-const ref
351 using U1 = std::unique_ptr<VT, TD1 >;
352 using U2 = std::unique_ptr<VT, TD2& >;
353 U1 u1;
354 U2 u2(nullptr, d2);
355 u1.get_deleter().reset();
356 u1 = std::move(u2);
357 assert(checkArg<TD2&>(u1.get_deleter()));
358 }
359 { // Test assignment from const ref
360 using U1 = std::unique_ptr<VT, TD1 >;
361 using U2 = std::unique_ptr<VT, TD2 const& >;
362 U1 u1;
363 U2 u2(nullptr, d2);
364 u1.get_deleter().reset();
365 u1 = std::move(u2);
366 assert(checkArg<TD2 const&>(u1.get_deleter()));
367 }
368
369 { // Test assignment from non-const ref
370 using U1 = std::unique_ptr<VT, TD1& >;
371 using U2 = std::unique_ptr<VT, TD2& >;
372 U1 u1(nullptr, d1);
373 U2 u2(nullptr, d2);
374 u1.get_deleter().reset();
375 u1 = std::move(u2);
376 assert(checkArg<TD2&>(u1.get_deleter()));
377 }
378 { // Test assignment from const ref
379 using U1 = std::unique_ptr<VT, TD1& >;
380 using U2 = std::unique_ptr<VT, TD2 const& >;
381 U1 u1(nullptr, d1);
382 U2 u2(nullptr, d2);
383 u1.get_deleter().reset();
384 u1 = std::move(u2);
385 assert(checkArg<TD2 const&>(u1.get_deleter()));
386 }
387
388 { // Test assignment from non-const ref
389 using U1 = std::unique_ptr<VT, CD1 const& >;
390 using U2 = std::unique_ptr<VT, CD2 & >;
391 U1 u1(nullptr, cd1);
392 U2 u2(nullptr, cd2);
393 u1.get_deleter().reset();
394 u1 = std::move(u2);
395 assert(checkArg<CD2 &>(u1.get_deleter()));
396 }
397 { // Test assignment from const ref
398 using U1 = std::unique_ptr<VT, CD1 const& >;
399 using U2 = std::unique_ptr<VT, CD2 const& >;
400 U1 u1(nullptr, cd1);
401 U2 u2(nullptr, cd2);
402 u1.get_deleter().reset();
403 u1 = std::move(u2);
404 assert(checkArg<CD2 const&>(u1.get_deleter()));
405 }
406 }
407
main(int,char **)408 int main(int, char**) {
409 {
410 test_sfinae</*IsArray*/false>();
411 test_noexcept<false>();
412 test_deleter_value_category<false>();
413 }
414 {
415 test_sfinae</*IsArray*/true>();
416 test_noexcept<true>();
417 test_deleter_value_category<true>();
418 }
419
420 return 0;
421 }
422