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