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 void operator()(void*) const {}
27 };
28
29 template <int ID = 0>
30 struct GenericConvertingDeleter {
31 template <int OID>
GenericConvertingDeleterGenericConvertingDeleter32 GenericConvertingDeleter(GenericConvertingDeleter<OID>) {}
operator ()GenericConvertingDeleter33 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 TrackingDeleter() : arg_type(&makeArgumentID<>()) {}
54
TrackingDeleterTrackingDeleter55 TrackingDeleter(TrackingDeleter const&)
56 : arg_type(&makeArgumentID<TrackingDeleter const&>()) {}
57
TrackingDeleterTrackingDeleter58 TrackingDeleter(TrackingDeleter&&)
59 : arg_type(&makeArgumentID<TrackingDeleter &&>()) {}
60
61 template <class T, class = EnableIfSpecialization<TrackingDeleter, T> >
TrackingDeleterTrackingDeleter62 TrackingDeleter(T&&) : arg_type(&makeArgumentID<T&&>()) {}
63
operator =TrackingDeleter64 TrackingDeleter& operator=(TrackingDeleter const&) {
65 arg_type = &makeArgumentID<TrackingDeleter const&>();
66 return *this;
67 }
68
operator =TrackingDeleter69 TrackingDeleter& operator=(TrackingDeleter &&) {
70 arg_type = &makeArgumentID<TrackingDeleter &&>();
71 return *this;
72 }
73
74 template <class T, class = EnableIfSpecialization<TrackingDeleter, T> >
operator =TrackingDeleter75 TrackingDeleter& operator=(T&&) {
76 arg_type = &makeArgumentID<T&&>();
77 return *this;
78 }
79
operator ()TrackingDeleter80 void operator()(void*) const {}
81
82 public:
resetTrackingDeleter83 TypeID const* reset() const {
84 TypeID const* tmp = arg_type;
85 arg_type = nullptr;
86 return tmp;
87 }
88
89 mutable TypeID const* arg_type;
90 };
91
92
93 template <class ExpectT, int ID>
checkArg(TrackingDeleter<ID> const & d)94 bool checkArg(TrackingDeleter<ID> const& d) {
95 return d.arg_type && *d.arg_type == makeArgumentID<ExpectT>();
96 }
97
98
99 template <bool IsArray>
test_sfinae()100 void test_sfinae() {
101 typedef typename std::conditional<IsArray, A[], A>::type VT;
102
103 { // Test that different non-reference deleter types are allowed so long
104 // as they convert to each other.
105 using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> >;
106 using U2 = std::unique_ptr<VT, GenericConvertingDeleter<1> >;
107 static_assert(std::is_constructible<U1, U2&&>::value, "");
108 }
109 { // Test that different non-reference deleter types are disallowed when
110 // they cannot convert.
111 using U1 = std::unique_ptr<VT, GenericDeleter<0> >;
112 using U2 = std::unique_ptr<VT, GenericDeleter<1> >;
113 static_assert(!std::is_constructible<U1, U2&&>::value, "");
114 }
115 { // Test that if the destination deleter is a reference type then only
116 // exact matches are allowed.
117 using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> const& >;
118 using U2 = std::unique_ptr<VT, GenericConvertingDeleter<0> >;
119 using U3 = std::unique_ptr<VT, GenericConvertingDeleter<0> &>;
120 using U4 = std::unique_ptr<VT, GenericConvertingDeleter<1> >;
121 using U5 = std::unique_ptr<VT, GenericConvertingDeleter<1> const&>;
122 static_assert(!std::is_constructible<U1, U2&&>::value, "");
123 static_assert(!std::is_constructible<U1, U3&&>::value, "");
124 static_assert(!std::is_constructible<U1, U4&&>::value, "");
125 static_assert(!std::is_constructible<U1, U5&&>::value, "");
126
127 using U1C = std::unique_ptr<const VT, GenericConvertingDeleter<0> const&>;
128 static_assert(std::is_nothrow_constructible<U1C, U1&&>::value, "");
129 }
130 { // Test that non-reference destination deleters can be constructed
131 // from any source deleter type with a suitable conversion. Including
132 // reference types.
133 using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> >;
134 using U2 = std::unique_ptr<VT, GenericConvertingDeleter<0> &>;
135 using U3 = std::unique_ptr<VT, GenericConvertingDeleter<0> const &>;
136 using U4 = std::unique_ptr<VT, GenericConvertingDeleter<1> >;
137 using U5 = std::unique_ptr<VT, GenericConvertingDeleter<1> &>;
138 using U6 = std::unique_ptr<VT, GenericConvertingDeleter<1> const&>;
139 static_assert(std::is_constructible<U1, U2&&>::value, "");
140 static_assert(std::is_constructible<U1, U3&&>::value, "");
141 static_assert(std::is_constructible<U1, U4&&>::value, "");
142 static_assert(std::is_constructible<U1, U5&&>::value, "");
143 static_assert(std::is_constructible<U1, U6&&>::value, "");
144 }
145 }
146
147
148 template <bool IsArray>
test_noexcept()149 void test_noexcept() {
150 typedef typename std::conditional<IsArray, A[], A>::type VT;
151 {
152 typedef std::unique_ptr<const VT> APtr;
153 typedef std::unique_ptr<VT> BPtr;
154 static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, "");
155 }
156 {
157 typedef std::unique_ptr<const VT, CDeleter<const VT> > APtr;
158 typedef std::unique_ptr<VT, CDeleter<VT> > BPtr;
159 static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, "");
160 }
161 {
162 typedef std::unique_ptr<const VT, NCDeleter<const VT>&> APtr;
163 typedef std::unique_ptr<VT, NCDeleter<const VT>&> BPtr;
164 static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, "");
165 }
166 {
167 typedef std::unique_ptr<const VT, const NCConstDeleter<const VT>&> APtr;
168 typedef std::unique_ptr<VT, const NCConstDeleter<const VT>&> BPtr;
169 static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, "");
170 }
171 }
172
173
174 template <bool IsArray>
test_deleter_value_category()175 void test_deleter_value_category() {
176 typedef typename std::conditional<IsArray, A[], A>::type VT;
177 using TD1 = TrackingDeleter<1>;
178 using TD2 = TrackingDeleter<2>;
179 TD1 d1;
180 TD2 d2;
181
182 { // Test non-reference deleter conversions
183 using U1 = std::unique_ptr<VT, TD1 >;
184 using U2 = std::unique_ptr<VT, TD2 >;
185 U2 u2;
186 u2.get_deleter().reset();
187 U1 u1(std::move(u2));
188 assert(checkArg<TD2&&>(u1.get_deleter()));
189 }
190 { // Test assignment from non-const ref
191 using U1 = std::unique_ptr<VT, TD1 >;
192 using U2 = std::unique_ptr<VT, TD2& >;
193 U2 u2(nullptr, d2);
194 U1 u1(std::move(u2));
195 assert(checkArg<TD2&>(u1.get_deleter()));
196 }
197 { // Test assignment from const ref
198 using U1 = std::unique_ptr<VT, TD1 >;
199 using U2 = std::unique_ptr<VT, TD2 const& >;
200 U2 u2(nullptr, d2);
201 U1 u1(std::move(u2));
202 assert(checkArg<TD2 const&>(u1.get_deleter()));
203 }
204 }
205
206
main(int,char **)207 int main(int, char**) {
208 {
209 test_sfinae</*IsArray*/false>();
210 test_noexcept<false>();
211 test_deleter_value_category<false>();
212 }
213 {
214 test_sfinae</*IsArray*/true>();
215 test_noexcept<true>();
216 test_deleter_value_category<true>();
217 }
218
219 return 0;
220 }
221