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

source code of libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared.array.unbounded.pass.cpp