]>
Commit | Line | Data |
---|---|---|
9a0b518a JW |
1 | // { dg-options "-std=gnu++20 -fno-lifetime-dse -O0" } |
2 | // { dg-do run { target c++20 } } | |
7cc9022f | 3 | // { dg-require-effective-target hosted } |
9a0b518a JW |
4 | |
5 | // C++20 20.11.3.7 shared_ptr Creation [util.smartptr.shared.create] | |
6 | ||
7 | #include <memory> | |
8 | ||
9 | #ifndef __cpp_lib_smart_ptr_for_overwrite | |
10 | # error "Feature-test macro for make_shared_for_overwrite missing in <memory>" | |
11 | #elif __cpp_lib_smart_ptr_for_overwrite < 202002L | |
12 | # error "Feature-test macro for make_shared_for_overwrite has wrong value in <memory>" | |
13 | #endif | |
14 | ||
15 | #include <cstring> | |
16 | #include <testsuite_hooks.h> | |
17 | ||
18 | int counter = 0; | |
19 | ||
20 | template<typename T> | |
21 | struct Alloc : std::allocator<T> | |
22 | { | |
23 | Alloc() = default; | |
24 | ||
25 | template<typename U> | |
26 | Alloc(const Alloc<U>&) { } | |
27 | ||
28 | T* allocate(std::size_t n) | |
29 | { | |
30 | ++counter; | |
31 | void* p = std::allocator<T>::allocate(n); | |
32 | // need -fno-lifetime-dse to check for these values later. | |
33 | std::memset(p, 0xff, n * sizeof(T)); | |
34 | return (T*)p; | |
35 | } | |
36 | ||
37 | void construct(auto*, auto&&...) | |
38 | { | |
39 | // The objects must be default-initialized, not using this function. | |
40 | VERIFY( ! "allocator_traits::construct" ); | |
41 | } | |
42 | ||
43 | void destroy(auto*) | |
44 | { | |
45 | // The objects must be destroyed by ~T(), not using this function. | |
46 | VERIFY( ! "allocator_traits::destroy" ); | |
47 | } | |
48 | }; | |
49 | ||
50 | void | |
51 | test01() | |
52 | { | |
53 | Alloc<int> a; | |
54 | const int expected = 0xffffffff; | |
55 | ||
56 | std::shared_ptr<int> p1 = std::allocate_shared_for_overwrite<int>(a); | |
57 | VERIFY( counter == 1 ); | |
58 | VERIFY( *p1 == expected ); | |
59 | std::shared_ptr<int[44]> p2 = std::allocate_shared_for_overwrite<int[44]>(a); | |
60 | VERIFY( counter == 2 ); | |
61 | VERIFY( p2[0] == expected ); | |
62 | p2.reset(); | |
63 | std::shared_ptr<int[]> p3 = std::allocate_shared_for_overwrite<int[]>(a, 88); | |
64 | VERIFY( counter == 3 ); | |
65 | VERIFY( p3[0] == expected ); | |
66 | VERIFY( p3[87] == expected ); | |
67 | std::shared_ptr<int[3][4]> p4 = std::allocate_shared_for_overwrite<int[3][4]>(a); | |
68 | VERIFY( counter == 4 ); | |
69 | VERIFY( p4[0][0] == expected ); | |
70 | VERIFY( p4[2][3] == expected ); | |
71 | std::shared_ptr<int[][5]> p5 = std::allocate_shared_for_overwrite<int[][5]>(a, 6); | |
72 | VERIFY( counter == 5 ); | |
73 | VERIFY( p5[0][0] == expected ); | |
74 | VERIFY( p5[5][4] == expected ); | |
75 | ||
76 | struct BigBoi { int x[100]; }; | |
77 | std::shared_ptr<BigBoi> p6 = std::allocate_shared_for_overwrite<BigBoi>(a); | |
78 | VERIFY( counter == 6 ); | |
79 | VERIFY( p6->x[0] == expected ); | |
80 | std::shared_ptr<BigBoi[22]> p7 = std::allocate_shared_for_overwrite<BigBoi[22]>(a); | |
81 | VERIFY( counter == 7 ); | |
82 | VERIFY( p7[0].x[0] == expected ); | |
83 | VERIFY( p7[21].x[99] == expected ); | |
84 | std::shared_ptr<BigBoi[]> p8 = std::allocate_shared_for_overwrite<BigBoi[]>(a, 11); | |
85 | VERIFY( counter == 8 ); | |
86 | VERIFY( p8[0].x[0] == expected ); | |
87 | VERIFY( p8[10].x[10] == expected ); | |
88 | } | |
89 | ||
90 | void | |
91 | test02() | |
92 | { | |
93 | // These aren't created by the custom allocator, so we can't check that the | |
94 | // memory was left uninitialized. Just dereference them. | |
95 | ||
96 | std::shared_ptr<int> p1 = std::make_shared_for_overwrite<int>(); | |
97 | (void) *p1; | |
98 | std::shared_ptr<int[44]> p2 = std::make_shared_for_overwrite<int[44]>(); | |
99 | (void) p2[0]; | |
100 | std::shared_ptr<int[]> p3 = std::make_shared_for_overwrite<int[]>(88); | |
101 | (void) p3[0]; | |
102 | (void) p3[87]; | |
103 | std::shared_ptr<int[3][4]> p4 = std::make_shared_for_overwrite<int[3][4]>(); | |
104 | (void) p4[0][0]; | |
105 | (void) p4[2][3]; | |
106 | std::shared_ptr<int[][5]> p5 = std::make_shared_for_overwrite<int[][5]>(6); | |
107 | (void) p5[0][0]; | |
108 | (void) p5[5][4]; | |
109 | ||
110 | struct BigBoi { int x[100]; }; | |
111 | std::shared_ptr<BigBoi> p6 = std::make_shared_for_overwrite<BigBoi>(); | |
112 | (void) p6->x[0]; | |
113 | std::shared_ptr<BigBoi[22]> p7 = std::make_shared_for_overwrite<BigBoi[22]>(); | |
114 | (void) p7[0].x[0]; | |
115 | (void) p7[21].x[99]; | |
116 | std::shared_ptr<BigBoi[]> p8 = std::make_shared_for_overwrite<BigBoi[]>(11); | |
117 | (void) p8[0].x[0]; | |
118 | (void) p8[10].x[10]; | |
119 | } | |
120 | ||
121 | void | |
122 | test03() | |
123 | { | |
124 | // Type with non-trivial initialization should still be default-initialized. | |
125 | struct NonTriv | |
126 | { | |
127 | int init = 0xbb; | |
128 | int uninit; | |
129 | }; | |
130 | std::shared_ptr<NonTriv> a = std::make_shared_for_overwrite<NonTriv>(); | |
131 | VERIFY( a->init == 0xbb ); | |
132 | std::shared_ptr<NonTriv[]> b = std::make_shared_for_overwrite<NonTriv[2]>(); | |
133 | VERIFY( b[1].init == 0xbb ); | |
134 | std::shared_ptr<NonTriv[]> c = std::make_shared_for_overwrite<NonTriv[]>(2); | |
135 | VERIFY( c[1].init == 0xbb ); | |
136 | } | |
137 | ||
138 | int | |
139 | main() | |
140 | { | |
141 | test01(); | |
142 | test02(); | |
143 | test03(); | |
144 | } |