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, c++11, c++14, c++17
10 
11 // <memory>
12 
13 // shared_ptr
14 
15 // template<class T>
16 // shared_ptr<T> make_shared(); // T is U[N]
17 //
18 // template<class T>
19 // shared_ptr<T> make_shared(const remove_extent_t<T>& u); // T is U[N]
20 
21 #include <cassert>
22 #include <concepts>
23 #include <cstdint> // std::uintptr_t
24 #include <memory>
25 #include <utility>
26 
27 #include "operator_hijacker.h"
28 #include "types.h"
29 
30 template <class T, class ...Args>
31 concept CanMakeShared = requires(Args&& ...args) {
32   { std::make_shared<T>(std::forward<Args>(args)...) } -> std::same_as<std::shared_ptr<T>>;
33 };
34 
main(int,char **)35 int main(int, char**) {
36   // Make sure we initialize elements correctly
37   {
38     // Without passing an initial value
39     {
40       using Array = int[8];
41       std::shared_ptr<Array> ptr = std::make_shared<Array>();
42       for (unsigned i = 0; i < 8; ++i) {
43         assert(ptr[i] == 0);
44       }
45     }
46     {
47       using Array = int[8][3];
48       std::shared_ptr<Array> ptr = std::make_shared<Array>();
49       for (unsigned i = 0; i < 8; ++i) {
50         assert(ptr[i][0] == 0);
51         assert(ptr[i][1] == 0);
52         assert(ptr[i][2] == 0);
53       }
54     }
55     {
56       using Array = int[8][3][2];
57       std::shared_ptr<Array> ptr = std::make_shared<Array>();
58       for (unsigned i = 0; i < 8; ++i) {
59         assert(ptr[i][0][0] == 0);
60         assert(ptr[i][0][1] == 0);
61         assert(ptr[i][1][0] == 0);
62         assert(ptr[i][1][1] == 0);
63         assert(ptr[i][2][0] == 0);
64         assert(ptr[i][2][1] == 0);
65       }
66     }
67 
68     // Passing an initial value
69     {
70       using Array = int[8];
71       int init = 42;
72       std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
73       for (unsigned i = 0; i < 8; ++i) {
74         assert(ptr[i] == init);
75       }
76     }
77     {
78       using Array = int[8][3];
79       int init[3] = {42, 43, 44};
80       std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
81       for (unsigned i = 0; i < 8; ++i) {
82         assert(ptr[i][0] == 42);
83         assert(ptr[i][1] == 43);
84         assert(ptr[i][2] == 44);
85       }
86     }
87     {
88       using Array = int[8][3][2];
89       int init[3][2] = {{31, 32}, {41, 42}, {51, 52}};
90       std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
91       for (unsigned i = 0; i < 8; ++i) {
92         assert(ptr[i][0][0] == 31);
93         assert(ptr[i][0][1] == 32);
94         assert(ptr[i][1][0] == 41);
95         assert(ptr[i][1][1] == 42);
96         assert(ptr[i][2][0] == 51);
97         assert(ptr[i][2][1] == 52);
98       }
99     }
100   }
101 
102   // Make sure array elements are destroyed in reverse order
103   {
104     // Without passing an initial value
105     {
106       using Array = DestroyInReverseOrder[8];
107       DestroyInReverseOrder::reset();
108       {
109         std::shared_ptr<Array> ptr = std::make_shared<Array>();
110         assert(DestroyInReverseOrder::alive() == 8);
111       }
112       assert(DestroyInReverseOrder::alive() == 0);
113     }
114     {
115       using Array = DestroyInReverseOrder[8][3];
116       DestroyInReverseOrder::reset();
117       {
118         std::shared_ptr<Array> ptr = std::make_shared<Array>();
119         assert(DestroyInReverseOrder::alive() == 8 * 3);
120       }
121       assert(DestroyInReverseOrder::alive() == 0);
122     }
123     {
124       using Array = DestroyInReverseOrder[8][3][2];
125       DestroyInReverseOrder::reset();
126       {
127         std::shared_ptr<Array> ptr = std::make_shared<Array>();
128         assert(DestroyInReverseOrder::alive() == 8 * 3 * 2);
129       }
130       assert(DestroyInReverseOrder::alive() == 0);
131     }
132 
133     // Passing an initial value
134     {
135       using Array = DestroyInReverseOrder[8];
136       int count = 0;
137       DestroyInReverseOrder init(&count);
138       int init_count = 1;
139       {
140         std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
141         assert(count == 8 + init_count);
142       }
143       assert(count == init_count);
144     }
145     {
146       using Array = DestroyInReverseOrder[8][3];
147       int count = 0;
148       DestroyInReverseOrder init[3] = {&count, &count, &count};
149       int init_count = 3;
150       {
151         std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
152         assert(count == 8 * 3 + init_count);
153       }
154       assert(count == init_count);
155     }
156     {
157       using Array = DestroyInReverseOrder[8][3][2];
158       int count = 0;
159       DestroyInReverseOrder init[3][2] = {{&count, &count}, {&count, &count}, {&count, &count}};
160       int init_count = 3 * 2;
161       {
162         std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
163         assert(count == 8 * 3 * 2 + init_count);
164       }
165       assert(count == init_count);
166     }
167   }
168 
169   // Count the number of copies being made
170   {
171     // Without passing an initial value
172     {
173       using Array = CountCopies[8];
174       CountCopies::reset();
175       std::shared_ptr<Array> ptr = std::make_shared<Array>();
176       assert(CountCopies::copies() == 0);
177     }
178     {
179       using Array = CountCopies[8][3];
180       CountCopies::reset();
181       std::shared_ptr<Array> ptr = std::make_shared<Array>();
182       assert(CountCopies::copies() == 0);
183     }
184     {
185       using Array = CountCopies[8][3][2];
186       CountCopies::reset();
187       std::shared_ptr<Array> ptr = std::make_shared<Array>();
188       assert(CountCopies::copies() == 0);
189     }
190 
191     // Passing an initial value
192     {
193       using Array = CountCopies[8];
194       int copies = 0;
195       CountCopies init(&copies);
196       std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
197       assert(copies == 8);
198     }
199     {
200       using Array = CountCopies[8][3];
201       int copies = 0;
202       CountCopies init[3] = {&copies, &copies, &copies};
203       std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
204       assert(copies == 8 * 3);
205     }
206     {
207       using Array = CountCopies[8][3][2];
208       int copies = 0;
209       CountCopies init[3][2] = {{&copies, &copies}, {&copies, &copies}, {&copies, &copies}};
210       std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
211       assert(copies == 8 * 3 * 2);
212     }
213   }
214 
215   // Make sure array elements are aligned properly when the array contains an overaligned type.
216   //
217   // Here, we don't need to test both the with-initial-value and without-initial-value code paths,
218   // since we're just checking the alignment and both are going to use the same code path unless
219   // the implementation is completely crazy.
220   {
221     auto check_alignment = []<class T> {
222       {
223         using Array = T[8];
224         std::shared_ptr ptr = std::make_shared<Array>();
225         for (int i = 0; i < 8; ++i) {
226           T* p = std::addressof(ptr[i]);
227           assert(reinterpret_cast<std::uintptr_t>(p) % alignof(T) == 0);
228         }
229       }
230       {
231         using Array = T[8][3];
232         std::shared_ptr ptr = std::make_shared<Array>();
233         for (int i = 0; i < 8; ++i) {
234           for (int j = 0; j < 3; ++j) {
235             T* p = std::addressof(ptr[i][j]);
236             assert(reinterpret_cast<std::uintptr_t>(p) % alignof(T) == 0);
237           }
238         }
239       }
240       {
241         using Array = T[8][3][2];
242         std::shared_ptr ptr = std::make_shared<Array>();
243         for (int i = 0; i < 8; ++i) {
244           for (int j = 0; j < 3; ++j) {
245             for (int k = 0; k < 2; ++k) {
246               T* p = std::addressof(ptr[i][j][k]);
247               assert(reinterpret_cast<std::uintptr_t>(p) % alignof(T) == 0);
248             }
249           }
250         }
251       }
252     };
253 
254     struct Empty { };
255     check_alignment.operator()<Empty>();
256     check_alignment.operator()<OverAligned>();
257     check_alignment.operator()<MaxAligned>();
258 
259     // test non corner cases as well while we're at it
260     struct Foo { int i; char c; };
261     check_alignment.operator()<int>();
262     check_alignment.operator()<Foo>();
263   }
264 
265   // Make sure that we destroy all the elements constructed so far when an exception
266   // is thrown. Also make sure that we do it in reverse order of construction.
267 #ifndef TEST_HAS_NO_EXCEPTIONS
268   {
269     struct Sentinel : ThrowOnConstruction, DestroyInReverseOrder { };
270 
271     // Without passing an initial value
272     {
273       using Array = Sentinel[8];
274       for (int i = 0; i < 8; ++i) {
275         ThrowOnConstruction::throw_after(i);
276         DestroyInReverseOrder::reset();
277         try {
278           std::shared_ptr<Array> ptr = std::make_shared<Array>();
279           assert(false);
280         } catch (ThrowOnConstruction::exception const&) {
281           assert(DestroyInReverseOrder::alive() == 0);
282         }
283       }
284     }
285     {
286       using Array = Sentinel[8][3];
287       for (int i = 0; i < 8 * 3; ++i) {
288         ThrowOnConstruction::throw_after(i);
289         DestroyInReverseOrder::reset();
290         try {
291           std::shared_ptr<Array> ptr = std::make_shared<Array>();
292           assert(false);
293         } catch (ThrowOnConstruction::exception const&) {
294           assert(DestroyInReverseOrder::alive() == 0);
295         }
296       }
297     }
298     {
299       using Array = Sentinel[8][3][2];
300       for (int i = 0; i < 8 * 3 * 2; ++i) {
301         ThrowOnConstruction::throw_after(i);
302         DestroyInReverseOrder::reset();
303         try {
304           std::shared_ptr<Array> ptr = std::make_shared<Array>();
305           assert(false);
306         } catch (ThrowOnConstruction::exception const&) {
307           assert(DestroyInReverseOrder::alive() == 0);
308         }
309       }
310     }
311 
312     // Passing an initial value
313     {
314       using Array = Sentinel[8];
315       for (int i = 0; i < 8; ++i) {
316         DestroyInReverseOrder::reset();
317         ThrowOnConstruction::reset();
318         Sentinel init;
319         ThrowOnConstruction::throw_after(i);
320         try {
321           std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
322           assert(false);
323         } catch (ThrowOnConstruction::exception const&) {
324           assert(DestroyInReverseOrder::alive() == 1);
325         }
326       }
327     }
328     {
329       using Array = Sentinel[8][3];
330       for (int i = 0; i < 8 * 3; ++i) {
331         DestroyInReverseOrder::reset();
332         ThrowOnConstruction::reset();
333         Sentinel init[3] = {};
334         ThrowOnConstruction::throw_after(i);
335         try {
336           std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
337           assert(false);
338         } catch (ThrowOnConstruction::exception const&) {
339           assert(DestroyInReverseOrder::alive() == 3);
340         }
341       }
342     }
343     {
344       using Array = Sentinel[8][3][2];
345       for (int i = 0; i < 8 * 3 * 2; ++i) {
346         DestroyInReverseOrder::reset();
347         ThrowOnConstruction::reset();
348         Sentinel init[3][2] = {};
349         ThrowOnConstruction::throw_after(i);
350         try {
351           std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
352           assert(false);
353         } catch (ThrowOnConstruction::exception const&) {
354           assert(DestroyInReverseOrder::alive() == 3 * 2);
355         }
356       }
357     }
358   }
359 #endif // TEST_HAS_NO_EXCEPTIONS
360 
361   // Make sure the version without an initialization argument works even for non-movable types
362   {
363     using Array = NonMovable[8][3];
364     std::shared_ptr<Array> ptr = std::make_shared<Array>();
365     (void)ptr;
366   }
367 
368   // Make sure std::make_shared handles badly-behaved types properly
369   {
370     using Array = operator_hijacker[3];
371     std::shared_ptr<Array> p1 = std::make_shared<Array>();
372     std::shared_ptr<Array> p2 = std::make_shared<Array>(operator_hijacker());
373     assert(p1 != nullptr);
374     assert(p2 != nullptr);
375   }
376 
377   // Check that we SFINAE-away for invalid arguments
378   {
379     struct T { };
380     static_assert( CanMakeShared<T[8]>);
381     static_assert( CanMakeShared<T[8], T>);
382     static_assert(!CanMakeShared<T[8], T, int>); // too many arguments
383   }
384 
385   return 0;
386 }
387