1 //===----------------------------------------------------------------------===//
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
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
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]
26 #include <cstdint> // std::uintptr_t
30 #include "min_allocator.h"
31 #include "operator_hijacker.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
45 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>());
46 for (unsigned i
= 0; i
< 8; ++i
) {
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
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];
141 DestroyInReverseOrder
init(&count
);
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];
152 DestroyInReverseOrder init
[3] = {&count
, &count
, &count
};
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];
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];
199 CountCopies
init(&copies
);
200 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>(), init
);
204 using Array
= CountCopies
[8][3];
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];
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
> {
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);
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();
282 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>());
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();
295 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>());
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();
308 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>());
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();
323 ThrowOnConstruction::throw_after(i
);
325 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>(), init
);
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
);
340 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>(), init
);
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
);
355 std::shared_ptr
<Array
> ptr
= std::allocate_shared
<Array
>(std::allocator
<Array
>(), init
);
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
>());
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
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