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