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