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 / allocate_shared.array.bounded.pass.cpp
blob79558cfc4c6c0c9c08cff065a1a855b58ddac0ca
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, class A>
19 // shared_ptr<T> allocate_shared(const A& a); // T is U[N]
21 // template<class T, class A>
22 // shared_ptr<T> allocate_shared(const A& a, 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 "min_allocator.h"
31 #include "operator_hijacker.h"
32 #include "types.h"
34 template <class T, class ...Args>
35 concept CanAllocateShared = requires(Args&& ...args) {
36 { std::allocate_shared<T>(std::forward<Args>(args)...) } -> std::same_as<std::shared_ptr<T>>;
39 int main(int, char**) {
40 // Make sure we initialize elements correctly
42 // Without passing an initial value
44 using Array = int[8];
45 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>());
46 for (unsigned i = 0; i < 8; ++i) {
47 assert(ptr[i] == 0);
51 using Array = int[8][3];
52 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>());
53 for (unsigned i = 0; i < 8; ++i) {
54 assert(ptr[i][0] == 0);
55 assert(ptr[i][1] == 0);
56 assert(ptr[i][2] == 0);
60 using Array = int[8][3][2];
61 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>());
62 for (unsigned i = 0; i < 8; ++i) {
63 assert(ptr[i][0][0] == 0);
64 assert(ptr[i][0][1] == 0);
65 assert(ptr[i][1][0] == 0);
66 assert(ptr[i][1][1] == 0);
67 assert(ptr[i][2][0] == 0);
68 assert(ptr[i][2][1] == 0);
72 // Passing an initial value
74 using Array = int[8];
75 int init = 42;
76 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>(), init);
77 for (unsigned i = 0; i < 8; ++i) {
78 assert(ptr[i] == init);
82 using Array = int[8][3];
83 int init[3] = {42, 43, 44};
84 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>(), init);
85 for (unsigned i = 0; i < 8; ++i) {
86 assert(ptr[i][0] == 42);
87 assert(ptr[i][1] == 43);
88 assert(ptr[i][2] == 44);
92 using Array = int[8][3][2];
93 int init[3][2] = {{31, 32}, {41, 42}, {51, 52}};
94 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>(), init);
95 for (unsigned i = 0; i < 8; ++i) {
96 assert(ptr[i][0][0] == 31);
97 assert(ptr[i][0][1] == 32);
98 assert(ptr[i][1][0] == 41);
99 assert(ptr[i][1][1] == 42);
100 assert(ptr[i][2][0] == 51);
101 assert(ptr[i][2][1] == 52);
106 // Make sure array elements are destroyed in reverse order
108 // Without passing an initial value
110 using Array = DestroyInReverseOrder[8];
111 DestroyInReverseOrder::reset();
113 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>());
114 assert(DestroyInReverseOrder::alive() == 8);
116 assert(DestroyInReverseOrder::alive() == 0);
119 using Array = DestroyInReverseOrder[8][3];
120 DestroyInReverseOrder::reset();
122 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>());
123 assert(DestroyInReverseOrder::alive() == 8 * 3);
125 assert(DestroyInReverseOrder::alive() == 0);
128 using Array = DestroyInReverseOrder[8][3][2];
129 DestroyInReverseOrder::reset();
131 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>());
132 assert(DestroyInReverseOrder::alive() == 8 * 3 * 2);
134 assert(DestroyInReverseOrder::alive() == 0);
137 // Passing an initial value
139 using Array = DestroyInReverseOrder[8];
140 int count = 0;
141 DestroyInReverseOrder init(&count);
142 int init_count = 1;
144 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>(), init);
145 assert(count == 8 + init_count);
147 assert(count == init_count);
150 using Array = DestroyInReverseOrder[8][3];
151 int count = 0;
152 DestroyInReverseOrder init[3] = {&count, &count, &count};
153 int init_count = 3;
155 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>(), init);
156 assert(count == 8 * 3 + init_count);
158 assert(count == init_count);
161 using Array = DestroyInReverseOrder[8][3][2];
162 int count = 0;
163 DestroyInReverseOrder init[3][2] = {{&count, &count}, {&count, &count}, {&count, &count}};
164 int init_count = 3 * 2;
166 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>(), init);
167 assert(count == 8 * 3 * 2 + init_count);
169 assert(count == init_count);
173 // Count the number of copies being made
175 // Without passing an initial value
177 using Array = CountCopies[8];
178 CountCopies::reset();
179 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>());
180 assert(CountCopies::copies() == 0);
183 using Array = CountCopies[8][3];
184 CountCopies::reset();
185 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>());;
186 assert(CountCopies::copies() == 0);
189 using Array = CountCopies[8][3][2];
190 CountCopies::reset();
191 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>());;
192 assert(CountCopies::copies() == 0);
195 // Passing an initial value
197 using Array = CountCopies[8];
198 int copies = 0;
199 CountCopies init(&copies);
200 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>(), init);
201 assert(copies == 8);
204 using Array = CountCopies[8][3];
205 int copies = 0;
206 CountCopies init[3] = {&copies, &copies, &copies};
207 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>(), init);
208 assert(copies == 8 * 3);
211 using Array = CountCopies[8][3][2];
212 int copies = 0;
213 CountCopies init[3][2] = {{&copies, &copies}, {&copies, &copies}, {&copies, &copies}};
214 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>(), init);
215 assert(copies == 8 * 3 * 2);
219 // Make sure array elements are aligned properly when the array contains an overaligned type.
221 // Here, we don't need to test both the with-initial-value and without-initial-value code paths,
222 // since we're just checking the alignment and both are going to use the same code path unless
223 // the implementation is completely crazy.
225 auto check_alignment = []<class T> {
227 using Array = T[8];
228 std::shared_ptr ptr = std::allocate_shared<Array>(std::allocator<Array>());
229 for (int i = 0; i < 8; ++i) {
230 T* p = std::addressof(ptr[i]);
231 assert(reinterpret_cast<std::uintptr_t>(p) % alignof(T) == 0);
235 using Array = T[8][3];
236 std::shared_ptr ptr = std::allocate_shared<Array>(std::allocator<Array>());
237 for (int i = 0; i < 8; ++i) {
238 for (int j = 0; j < 3; ++j) {
239 T* p = std::addressof(ptr[i][j]);
240 assert(reinterpret_cast<std::uintptr_t>(p) % alignof(T) == 0);
245 using Array = T[8][3][2];
246 std::shared_ptr ptr = std::allocate_shared<Array>(std::allocator<Array>());
247 for (int i = 0; i < 8; ++i) {
248 for (int j = 0; j < 3; ++j) {
249 for (int k = 0; k < 2; ++k) {
250 T* p = std::addressof(ptr[i][j][k]);
251 assert(reinterpret_cast<std::uintptr_t>(p) % alignof(T) == 0);
258 struct Empty { };
259 check_alignment.operator()<Empty>();
260 check_alignment.operator()<OverAligned>();
261 check_alignment.operator()<MaxAligned>();
263 // test non corner cases as well while we're at it
264 struct Foo { int i; char c; };
265 check_alignment.operator()<int>();
266 check_alignment.operator()<Foo>();
269 // Make sure that we destroy all the elements constructed so far when an exception
270 // is thrown. Also make sure that we do it in reverse order of construction.
271 #ifndef TEST_HAS_NO_EXCEPTIONS
273 struct Sentinel : ThrowOnConstruction, DestroyInReverseOrder { };
275 // Without passing an initial value
277 using Array = Sentinel[8];
278 for (int i = 0; i < 8; ++i) {
279 ThrowOnConstruction::throw_after(i);
280 DestroyInReverseOrder::reset();
281 try {
282 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>());
283 assert(false);
284 } catch (ThrowOnConstruction::exception const&) {
285 assert(DestroyInReverseOrder::alive() == 0);
290 using Array = Sentinel[8][3];
291 for (int i = 0; i < 8 * 3; ++i) {
292 ThrowOnConstruction::throw_after(i);
293 DestroyInReverseOrder::reset();
294 try {
295 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>());
296 assert(false);
297 } catch (ThrowOnConstruction::exception const&) {
298 assert(DestroyInReverseOrder::alive() == 0);
303 using Array = Sentinel[8][3][2];
304 for (int i = 0; i < 8 * 3 * 2; ++i) {
305 ThrowOnConstruction::throw_after(i);
306 DestroyInReverseOrder::reset();
307 try {
308 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>());
309 assert(false);
310 } catch (ThrowOnConstruction::exception const&) {
311 assert(DestroyInReverseOrder::alive() == 0);
316 // Passing an initial value
318 using Array = Sentinel[8];
319 for (int i = 0; i < 8; ++i) {
320 DestroyInReverseOrder::reset();
321 ThrowOnConstruction::reset();
322 Sentinel init;
323 ThrowOnConstruction::throw_after(i);
324 try {
325 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>(), init);
326 assert(false);
327 } catch (ThrowOnConstruction::exception const&) {
328 assert(DestroyInReverseOrder::alive() == 1);
333 using Array = Sentinel[8][3];
334 for (int i = 0; i < 8 * 3; ++i) {
335 DestroyInReverseOrder::reset();
336 ThrowOnConstruction::reset();
337 Sentinel init[3] = {};
338 ThrowOnConstruction::throw_after(i);
339 try {
340 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>(), init);
341 assert(false);
342 } catch (ThrowOnConstruction::exception const&) {
343 assert(DestroyInReverseOrder::alive() == 3);
348 using Array = Sentinel[8][3][2];
349 for (int i = 0; i < 8 * 3 * 2; ++i) {
350 DestroyInReverseOrder::reset();
351 ThrowOnConstruction::reset();
352 Sentinel init[3][2] = {};
353 ThrowOnConstruction::throw_after(i);
354 try {
355 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>(), init);
356 assert(false);
357 } catch (ThrowOnConstruction::exception const&) {
358 assert(DestroyInReverseOrder::alive() == 3 * 2);
363 #endif // TEST_HAS_NO_EXCEPTIONS
365 // Test with another allocator that's not std::allocator
367 // Without passing an initial value
369 using Array = int[8][3];
370 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(min_allocator<Array>());
371 for (unsigned i = 0; i < 8; ++i) {
372 assert(ptr[i][0] == 0);
373 assert(ptr[i][1] == 0);
374 assert(ptr[i][2] == 0);
378 // Passing an initial value
380 using Array = int[8][3];
381 int init[3] = {42, 43, 44};
382 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(min_allocator<Array>(), init);
383 for (unsigned i = 0; i < 8; ++i) {
384 assert(ptr[i][0] == 42);
385 assert(ptr[i][1] == 43);
386 assert(ptr[i][2] == 44);
391 // Make sure the version without an initialization argument works even for non-movable types
393 using Array = NonMovable[8][3];
394 std::shared_ptr<Array> ptr = std::allocate_shared<Array>(std::allocator<Array>());
395 (void)ptr;
398 // Make sure std::allocate_shared handles badly-behaved types properly
400 using Array = operator_hijacker[3];
401 std::shared_ptr<Array> p1 = std::allocate_shared<Array>(std::allocator<Array>());
402 std::shared_ptr<Array> p2 = std::allocate_shared<Array>(std::allocator<Array>(), operator_hijacker());
403 assert(p1 != nullptr);
404 assert(p2 != nullptr);
407 // Check that we SFINAE-away for invalid arguments
409 struct T { };
410 static_assert( CanAllocateShared<T[8], std::allocator<T[8]>>);
411 static_assert( CanAllocateShared<T[8], std::allocator<T[8]>, T>);
412 static_assert(!CanAllocateShared<T[8], std::allocator<T[8]>, T, int>); // too many arguments
413 static_assert(!CanAllocateShared<T[8], std::allocator<T[8]>, int>); // T is not constructible from int
416 return 0;