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
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>) {}
operator ()GenericConvertingDeleter33 TEST_CONSTEXPR_CXX23 void operator()(void*) const {}
34 };
35
36 template <class Templ, class Other>
37 struct is_specialization;
38
39 template <template <int> class Templ, int ID1, class Other>
40 struct is_specialization<Templ<ID1>, Other> : std::false_type {};
41
42 template <template <int> class Templ, int ID1, int ID2>
43 struct is_specialization<Templ<ID1>, Templ<ID2> > : std::true_type {};
44
45 template <class Templ, class Other>
46 using EnableIfSpecialization = typename std::enable_if<
47 is_specialization<Templ, typename std::decay<Other>::type >::value
48 >::type;
49
50
51 template <int ID>
52 struct TrackingDeleter {
TrackingDeleterTrackingDeleter53 TEST_CONSTEXPR_CXX23 TrackingDeleter() : arg_type(&makeArgumentID<>()) {}
54
TrackingDeleterTrackingDeleter55 TEST_CONSTEXPR_CXX23 TrackingDeleter(TrackingDeleter const&) : arg_type(&makeArgumentID<TrackingDeleter const&>()) {}
56
TrackingDeleterTrackingDeleter57 TEST_CONSTEXPR_CXX23 TrackingDeleter(TrackingDeleter&&) : arg_type(&makeArgumentID<TrackingDeleter&&>()) {}
58
59 template <class T, class = EnableIfSpecialization<TrackingDeleter, T> >
TrackingDeleterTrackingDeleter60 TEST_CONSTEXPR_CXX23 TrackingDeleter(T&&) : arg_type(&makeArgumentID<T&&>()) {}
61
operator =TrackingDeleter62 TEST_CONSTEXPR_CXX23 TrackingDeleter& operator=(TrackingDeleter const&) {
63 arg_type = &makeArgumentID<TrackingDeleter const&>();
64 return *this;
65 }
66
operator =TrackingDeleter67 TEST_CONSTEXPR_CXX23 TrackingDeleter& operator=(TrackingDeleter&&) {
68 arg_type = &makeArgumentID<TrackingDeleter &&>();
69 return *this;
70 }
71
72 template <class T, class = EnableIfSpecialization<TrackingDeleter, T> >
operator =TrackingDeleter73 TEST_CONSTEXPR_CXX23 TrackingDeleter& operator=(T&&) {
74 arg_type = &makeArgumentID<T&&>();
75 return *this;
76 }
77
operator ()TrackingDeleter78 TEST_CONSTEXPR_CXX23 void operator()(void*) const {}
79
80 public:
resetTrackingDeleter81 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
91 template <class ExpectT, int ID>
checkArg(TrackingDeleter<ID> const & d)92 bool checkArg(TrackingDeleter<ID> const& d) {
93 return d.arg_type && *d.arg_type == makeArgumentID<ExpectT>();
94 }
95
96 template <bool IsArray>
test_sfinae()97 TEST_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
144 template <bool IsArray>
test_noexcept()145 TEST_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
169 template <bool IsArray>
test_deleter_value_category()170 TEST_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
test()201 TEST_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
main(int,char **)218 int main(int, char**) {
219 test();
220 #if TEST_STD_VER >= 23
221 static_assert(test());
222 #endif
223
224 return 0;
225 }
226