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