[VPlan] Perform DT expensive input DT verification earlier (NFC).
[llvm-project.git] / libcxx / test / std / utilities / memory / util.smartptr / util.smartptr.shared / util.smartptr.shared.create / make_shared.array.unbounded.pass.cpp
blobcd6c548010692da701325dd1aa2d60cbfdc82b3e
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 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
11 // <memory>
13 // shared_ptr
15 // template<class T> shared_ptr<T> make_shared(size_t N); // T is U[]
17 // template<class T>
18 // shared_ptr<T> make_shared(size_t N, const remove_extent_t<T>& u); // T is U[]
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
25 #include <cassert>
26 #include <concepts>
27 #include <cstdint> // std::uintptr_t
28 #include <memory>
29 #include <utility>
31 #include "operator_hijacker.h"
32 #include "test_macros.h"
33 #include "types.h"
35 template <class T, class ...Args>
36 concept CanMakeShared = requires(Args&& ...args) {
37 { std::make_shared<T>(std::forward<Args>(args)...) } -> std::same_as<std::shared_ptr<T>>;
40 int main(int, char**) {
41 // Check behavior for a zero-sized array
43 // Without passing an initial value
45 using Array = int[];
46 std::shared_ptr<Array> ptr = std::make_shared<Array>(0);
47 assert(ptr != nullptr);
50 // Passing an initial value
52 using Array = int[];
53 std::shared_ptr<Array> ptr = std::make_shared<Array>(0, 42);
54 assert(ptr != nullptr);
58 // Check behavior for a 1-sized array
60 // Without passing an initial value
62 using Array = int[];
63 std::shared_ptr<Array> ptr = std::make_shared<Array>(1);
64 assert(ptr != nullptr);
65 assert(ptr[0] == 0);
68 // Passing an initial value
70 using Array = int[];
71 std::shared_ptr<Array> ptr = std::make_shared<Array>(1, 42);
72 assert(ptr != nullptr);
73 assert(ptr[0] == 42);
77 // Make sure we initialize elements correctly
79 // Without passing an initial value
81 using Array = int[];
82 std::shared_ptr<Array> ptr = std::make_shared<Array>(8);
83 for (unsigned i = 0; i < 8; ++i) {
84 assert(ptr[i] == 0);
88 using Array = int[][3];
89 std::shared_ptr<Array> ptr = std::make_shared<Array>(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);
97 using Array = int[][3][2];
98 std::shared_ptr<Array> ptr = std::make_shared<Array>(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);
109 // Passing an initial value
111 using Array = int[];
112 int init = 42;
113 std::shared_ptr<Array> ptr = std::make_shared<Array>(8, init);
114 for (unsigned i = 0; i < 8; ++i) {
115 assert(ptr[i] == init);
119 using Array = int[][3];
120 int init[3] = {42, 43, 44};
121 std::shared_ptr<Array> ptr = std::make_shared<Array>(8, 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);
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>(8, 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);
143 // Make sure array elements are destroyed in reverse order
145 // Without passing an initial value
147 using Array = DestroyInReverseOrder[];
148 DestroyInReverseOrder::reset();
150 std::shared_ptr<Array> ptr = std::make_shared<Array>(8);
151 assert(DestroyInReverseOrder::alive() == 8);
153 assert(DestroyInReverseOrder::alive() == 0);
156 using Array = DestroyInReverseOrder[][3];
157 DestroyInReverseOrder::reset();
159 std::shared_ptr<Array> ptr = std::make_shared<Array>(8);
160 assert(DestroyInReverseOrder::alive() == 8 * 3);
162 assert(DestroyInReverseOrder::alive() == 0);
165 using Array = DestroyInReverseOrder[][3][2];
166 DestroyInReverseOrder::reset();
168 std::shared_ptr<Array> ptr = std::make_shared<Array>(8);
169 assert(DestroyInReverseOrder::alive() == 8 * 3 * 2);
171 assert(DestroyInReverseOrder::alive() == 0);
174 // Passing an initial value
176 using Array = DestroyInReverseOrder[];
177 int count = 0;
178 DestroyInReverseOrder init(&count);
179 int init_count = 1;
181 std::shared_ptr<Array> ptr = std::make_shared<Array>(8, init);
182 assert(count == 8 + init_count);
184 assert(count == init_count);
187 using Array = DestroyInReverseOrder[][3];
188 int count = 0;
189 DestroyInReverseOrder init[3] = {&count, &count, &count};
190 int init_count = 3;
192 std::shared_ptr<Array> ptr = std::make_shared<Array>(8, init);
193 assert(count == 8 * 3 + init_count);
195 assert(count == init_count);
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;
203 std::shared_ptr<Array> ptr = std::make_shared<Array>(8, init);
204 assert(count == 8 * 3 * 2 + init_count);
206 assert(count == init_count);
210 // Count the number of copies being made
212 // Without passing an initial value
214 using Array = CountCopies[];
215 CountCopies::reset();
216 std::shared_ptr<Array> ptr = std::make_shared<Array>(8);
217 assert(CountCopies::copies() == 0);
220 using Array = CountCopies[][3];
221 CountCopies::reset();
222 std::shared_ptr<Array> ptr = std::make_shared<Array>(8);
223 assert(CountCopies::copies() == 0);
226 using Array = CountCopies[][3][2];
227 CountCopies::reset();
228 std::shared_ptr<Array> ptr = std::make_shared<Array>(8);
229 assert(CountCopies::copies() == 0);
232 // Passing an initial value
234 using Array = CountCopies[];
235 int copies = 0;
236 CountCopies init(&copies);
237 std::shared_ptr<Array> ptr = std::make_shared<Array>(8, init);
238 assert(copies == 8);
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>(8, init);
245 assert(copies == 8 * 3);
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>(8, init);
252 assert(copies == 8 * 3 * 2);
256 // Make sure array elements are aligned properly when the array contains an overaligned type.
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.
262 auto check_alignment = []<class T> {
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);
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);
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);
295 struct Empty { };
296 check_alignment.operator()<Empty>();
297 check_alignment.operator()<OverAligned>();
298 check_alignment.operator()<MaxAligned>();
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>();
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
310 struct Sentinel : ThrowOnConstruction, DestroyInReverseOrder { };
312 // Without passing an initial value
314 using Array = Sentinel[];
315 for (int i = 0; i < 8; ++i) {
316 ThrowOnConstruction::throw_after(i);
317 DestroyInReverseOrder::reset();
318 try {
319 std::shared_ptr<Array> ptr = std::make_shared<Array>(8);
320 assert(false);
321 } catch (ThrowOnConstruction::exception const&) {
322 assert(DestroyInReverseOrder::alive() == 0);
327 using Array = Sentinel[][3];
328 for (int i = 0; i < 8 * 3; ++i) {
329 ThrowOnConstruction::throw_after(i);
330 DestroyInReverseOrder::reset();
331 try {
332 std::shared_ptr<Array> ptr = std::make_shared<Array>(8);
333 assert(false);
334 } catch (ThrowOnConstruction::exception const&) {
335 assert(DestroyInReverseOrder::alive() == 0);
340 using Array = Sentinel[][3][2];
341 for (int i = 0; i < 8 * 3 * 2; ++i) {
342 ThrowOnConstruction::throw_after(i);
343 DestroyInReverseOrder::reset();
344 try {
345 std::shared_ptr<Array> ptr = std::make_shared<Array>(8);
346 assert(false);
347 } catch (ThrowOnConstruction::exception const&) {
348 assert(DestroyInReverseOrder::alive() == 0);
353 // Passing an initial value
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(i);
361 try {
362 std::shared_ptr<Array> ptr = std::make_shared<Array>(8, init);
363 assert(false);
364 } catch (ThrowOnConstruction::exception const&) {
365 assert(DestroyInReverseOrder::alive() == 1);
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(i);
376 try {
377 std::shared_ptr<Array> ptr = std::make_shared<Array>(8, init);
378 assert(false);
379 } catch (ThrowOnConstruction::exception const&) {
380 assert(DestroyInReverseOrder::alive() == 3);
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(i);
391 try {
392 std::shared_ptr<Array> ptr = std::make_shared<Array>(8, init);
393 assert(false);
394 } catch (ThrowOnConstruction::exception const&) {
395 assert(DestroyInReverseOrder::alive() == 3 * 2);
400 #endif // TEST_HAS_NO_EXCEPTIONS
402 // Make sure the version without an initialization argument works even for non-movable types
404 using Array = NonMovable[][3];
405 std::shared_ptr<Array> ptr = std::make_shared<Array>(8);
406 (void)ptr;
409 // Make sure std::make_shared handles badly-behaved types properly
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);
418 // Check that we SFINAE-away for invalid arguments
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
426 return 0;