Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / libcxx / test / std / utilities / memory / util.smartptr / util.smartptr.shared / util.smartptr.shared.create / make_shared.array.bounded.pass.cpp
blob60fb9bb25ff861a5a329591c542399611c6925f7
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 // This test requires support for aligned allocation to test overaligned types.
12 // XFAIL: availability-aligned_allocation-missing
14 // <memory>
16 // shared_ptr
18 // template<class T>
19 // shared_ptr<T> make_shared(); // T is U[N]
21 // template<class T>
22 // shared_ptr<T> make_shared(const remove_extent_t<T>& u); // T is U[N]
24 #include <cassert>
25 #include <concepts>
26 #include <cstdint> // std::uintptr_t
27 #include <memory>
28 #include <utility>
30 #include "operator_hijacker.h"
31 #include "types.h"
33 template <class T, class ...Args>
34 concept CanMakeShared = requires(Args&& ...args) {
35 { std::make_shared<T>(std::forward<Args>(args)...) } -> std::same_as<std::shared_ptr<T>>;
38 int main(int, char**) {
39 // Make sure we initialize elements correctly
41 // Without passing an initial value
43 using Array = int[8];
44 std::shared_ptr<Array> ptr = std::make_shared<Array>();
45 for (unsigned i = 0; i < 8; ++i) {
46 assert(ptr[i] == 0);
50 using Array = int[8][3];
51 std::shared_ptr<Array> ptr = std::make_shared<Array>();
52 for (unsigned i = 0; i < 8; ++i) {
53 assert(ptr[i][0] == 0);
54 assert(ptr[i][1] == 0);
55 assert(ptr[i][2] == 0);
59 using Array = int[8][3][2];
60 std::shared_ptr<Array> ptr = std::make_shared<Array>();
61 for (unsigned i = 0; i < 8; ++i) {
62 assert(ptr[i][0][0] == 0);
63 assert(ptr[i][0][1] == 0);
64 assert(ptr[i][1][0] == 0);
65 assert(ptr[i][1][1] == 0);
66 assert(ptr[i][2][0] == 0);
67 assert(ptr[i][2][1] == 0);
71 // Passing an initial value
73 using Array = int[8];
74 int init = 42;
75 std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
76 for (unsigned i = 0; i < 8; ++i) {
77 assert(ptr[i] == init);
81 using Array = int[8][3];
82 int init[3] = {42, 43, 44};
83 std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
84 for (unsigned i = 0; i < 8; ++i) {
85 assert(ptr[i][0] == 42);
86 assert(ptr[i][1] == 43);
87 assert(ptr[i][2] == 44);
91 using Array = int[8][3][2];
92 int init[3][2] = {{31, 32}, {41, 42}, {51, 52}};
93 std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
94 for (unsigned i = 0; i < 8; ++i) {
95 assert(ptr[i][0][0] == 31);
96 assert(ptr[i][0][1] == 32);
97 assert(ptr[i][1][0] == 41);
98 assert(ptr[i][1][1] == 42);
99 assert(ptr[i][2][0] == 51);
100 assert(ptr[i][2][1] == 52);
105 // Make sure array elements are destroyed in reverse order
107 // Without passing an initial value
109 using Array = DestroyInReverseOrder[8];
110 DestroyInReverseOrder::reset();
112 std::shared_ptr<Array> ptr = std::make_shared<Array>();
113 assert(DestroyInReverseOrder::alive() == 8);
115 assert(DestroyInReverseOrder::alive() == 0);
118 using Array = DestroyInReverseOrder[8][3];
119 DestroyInReverseOrder::reset();
121 std::shared_ptr<Array> ptr = std::make_shared<Array>();
122 assert(DestroyInReverseOrder::alive() == 8 * 3);
124 assert(DestroyInReverseOrder::alive() == 0);
127 using Array = DestroyInReverseOrder[8][3][2];
128 DestroyInReverseOrder::reset();
130 std::shared_ptr<Array> ptr = std::make_shared<Array>();
131 assert(DestroyInReverseOrder::alive() == 8 * 3 * 2);
133 assert(DestroyInReverseOrder::alive() == 0);
136 // Passing an initial value
138 using Array = DestroyInReverseOrder[8];
139 int count = 0;
140 DestroyInReverseOrder init(&count);
141 int init_count = 1;
143 std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
144 assert(count == 8 + init_count);
146 assert(count == init_count);
149 using Array = DestroyInReverseOrder[8][3];
150 int count = 0;
151 DestroyInReverseOrder init[3] = {&count, &count, &count};
152 int init_count = 3;
154 std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
155 assert(count == 8 * 3 + init_count);
157 assert(count == init_count);
160 using Array = DestroyInReverseOrder[8][3][2];
161 int count = 0;
162 DestroyInReverseOrder init[3][2] = {{&count, &count}, {&count, &count}, {&count, &count}};
163 int init_count = 3 * 2;
165 std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
166 assert(count == 8 * 3 * 2 + init_count);
168 assert(count == init_count);
172 // Count the number of copies being made
174 // Without passing an initial value
176 using Array = CountCopies[8];
177 CountCopies::reset();
178 std::shared_ptr<Array> ptr = std::make_shared<Array>();
179 assert(CountCopies::copies() == 0);
182 using Array = CountCopies[8][3];
183 CountCopies::reset();
184 std::shared_ptr<Array> ptr = std::make_shared<Array>();
185 assert(CountCopies::copies() == 0);
188 using Array = CountCopies[8][3][2];
189 CountCopies::reset();
190 std::shared_ptr<Array> ptr = std::make_shared<Array>();
191 assert(CountCopies::copies() == 0);
194 // Passing an initial value
196 using Array = CountCopies[8];
197 int copies = 0;
198 CountCopies init(&copies);
199 std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
200 assert(copies == 8);
203 using Array = CountCopies[8][3];
204 int copies = 0;
205 CountCopies init[3] = {&copies, &copies, &copies};
206 std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
207 assert(copies == 8 * 3);
210 using Array = CountCopies[8][3][2];
211 int copies = 0;
212 CountCopies init[3][2] = {{&copies, &copies}, {&copies, &copies}, {&copies, &copies}};
213 std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
214 assert(copies == 8 * 3 * 2);
218 // Make sure array elements are aligned properly when the array contains an overaligned type.
220 // Here, we don't need to test both the with-initial-value and without-initial-value code paths,
221 // since we're just checking the alignment and both are going to use the same code path unless
222 // the implementation is completely crazy.
224 auto check_alignment = []<class T> {
226 using Array = T[8];
227 std::shared_ptr ptr = std::make_shared<Array>();
228 for (int i = 0; i < 8; ++i) {
229 T* p = std::addressof(ptr[i]);
230 assert(reinterpret_cast<std::uintptr_t>(p) % alignof(T) == 0);
234 using Array = T[8][3];
235 std::shared_ptr ptr = std::make_shared<Array>();
236 for (int i = 0; i < 8; ++i) {
237 for (int j = 0; j < 3; ++j) {
238 T* p = std::addressof(ptr[i][j]);
239 assert(reinterpret_cast<std::uintptr_t>(p) % alignof(T) == 0);
244 using Array = T[8][3][2];
245 std::shared_ptr ptr = std::make_shared<Array>();
246 for (int i = 0; i < 8; ++i) {
247 for (int j = 0; j < 3; ++j) {
248 for (int k = 0; k < 2; ++k) {
249 T* p = std::addressof(ptr[i][j][k]);
250 assert(reinterpret_cast<std::uintptr_t>(p) % alignof(T) == 0);
257 struct Empty { };
258 check_alignment.operator()<Empty>();
259 check_alignment.operator()<OverAligned>();
260 check_alignment.operator()<MaxAligned>();
262 // test non corner cases as well while we're at it
263 struct Foo { int i; char c; };
264 check_alignment.operator()<int>();
265 check_alignment.operator()<Foo>();
268 // Make sure that we destroy all the elements constructed so far when an exception
269 // is thrown. Also make sure that we do it in reverse order of construction.
270 #ifndef TEST_HAS_NO_EXCEPTIONS
272 struct Sentinel : ThrowOnConstruction, DestroyInReverseOrder { };
274 // Without passing an initial value
276 using Array = Sentinel[8];
277 for (int i = 0; i < 8; ++i) {
278 ThrowOnConstruction::throw_after(i);
279 DestroyInReverseOrder::reset();
280 try {
281 std::shared_ptr<Array> ptr = std::make_shared<Array>();
282 assert(false);
283 } catch (ThrowOnConstruction::exception const&) {
284 assert(DestroyInReverseOrder::alive() == 0);
289 using Array = Sentinel[8][3];
290 for (int i = 0; i < 8 * 3; ++i) {
291 ThrowOnConstruction::throw_after(i);
292 DestroyInReverseOrder::reset();
293 try {
294 std::shared_ptr<Array> ptr = std::make_shared<Array>();
295 assert(false);
296 } catch (ThrowOnConstruction::exception const&) {
297 assert(DestroyInReverseOrder::alive() == 0);
302 using Array = Sentinel[8][3][2];
303 for (int i = 0; i < 8 * 3 * 2; ++i) {
304 ThrowOnConstruction::throw_after(i);
305 DestroyInReverseOrder::reset();
306 try {
307 std::shared_ptr<Array> ptr = std::make_shared<Array>();
308 assert(false);
309 } catch (ThrowOnConstruction::exception const&) {
310 assert(DestroyInReverseOrder::alive() == 0);
315 // Passing an initial value
317 using Array = Sentinel[8];
318 for (int i = 0; i < 8; ++i) {
319 DestroyInReverseOrder::reset();
320 ThrowOnConstruction::reset();
321 Sentinel init;
322 ThrowOnConstruction::throw_after(i);
323 try {
324 std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
325 assert(false);
326 } catch (ThrowOnConstruction::exception const&) {
327 assert(DestroyInReverseOrder::alive() == 1);
332 using Array = Sentinel[8][3];
333 for (int i = 0; i < 8 * 3; ++i) {
334 DestroyInReverseOrder::reset();
335 ThrowOnConstruction::reset();
336 Sentinel init[3] = {};
337 ThrowOnConstruction::throw_after(i);
338 try {
339 std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
340 assert(false);
341 } catch (ThrowOnConstruction::exception const&) {
342 assert(DestroyInReverseOrder::alive() == 3);
347 using Array = Sentinel[8][3][2];
348 for (int i = 0; i < 8 * 3 * 2; ++i) {
349 DestroyInReverseOrder::reset();
350 ThrowOnConstruction::reset();
351 Sentinel init[3][2] = {};
352 ThrowOnConstruction::throw_after(i);
353 try {
354 std::shared_ptr<Array> ptr = std::make_shared<Array>(init);
355 assert(false);
356 } catch (ThrowOnConstruction::exception const&) {
357 assert(DestroyInReverseOrder::alive() == 3 * 2);
362 #endif // TEST_HAS_NO_EXCEPTIONS
364 // Make sure the version without an initialization argument works even for non-movable types
366 using Array = NonMovable[8][3];
367 std::shared_ptr<Array> ptr = std::make_shared<Array>();
368 (void)ptr;
371 // Make sure std::make_shared handles badly-behaved types properly
373 using Array = operator_hijacker[3];
374 std::shared_ptr<Array> p1 = std::make_shared<Array>();
375 std::shared_ptr<Array> p2 = std::make_shared<Array>(operator_hijacker());
376 assert(p1 != nullptr);
377 assert(p2 != nullptr);
380 // Check that we SFINAE-away for invalid arguments
382 struct T { };
383 static_assert( CanMakeShared<T[8]>);
384 static_assert( CanMakeShared<T[8], T>);
385 static_assert(!CanMakeShared<T[8], T, int>); // too many arguments
388 return 0;