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 //===----------------------------------------------------------------------===//
8 
9 // <memory>
10 
11 // shared_ptr
12 
13 // template<class T, class A, class... Args>
14 // shared_ptr<T> allocate_shared(const A& a, Args&&... args); // T is not an array
15 
16 #include <memory>
17 #include <new>
18 #include <cstdlib>
19 #include <cassert>
20 
21 #include "min_allocator.h"
22 #include "operator_hijacker.h"
23 #include "test_allocator.h"
24 #include "test_macros.h"
25 
26 int new_count = 0;
27 
28 struct A
29 {
30     static int count;
31 
AA32     A(int i, char c) : int_(i), char_(c) {++count;}
AA33     A(const A& a)
34         : int_(a.int_), char_(a.char_)
35         {++count;}
~AA36     ~A() {--count;}
37 
get_intA38     int get_int() const {return int_;}
get_charA39     char get_char() const {return char_;}
40 
41     A* operator& () = delete;
42 private:
43     int int_;
44     char char_;
45 };
46 
47 int A::count = 0;
48 
49 struct Zero
50 {
51     static int count;
ZeroZero52     Zero() {++count;}
ZeroZero53     Zero(Zero const &) {++count;}
~ZeroZero54     ~Zero() {--count;}
55 };
56 
57 int Zero::count = 0;
58 
59 struct One
60 {
61     static int count;
62     int value;
OneOne63     explicit One(int v) : value(v) {++count;}
OneOne64     One(One const & o) : value(o.value) {++count;}
~OneOne65     ~One() {--count;}
66 };
67 
68 int One::count = 0;
69 
70 
71 struct Two
72 {
73     static int count;
74     int value;
TwoTwo75     Two(int v, int) : value(v) {++count;}
TwoTwo76     Two(Two const & o) : value(o.value) {++count;}
~TwoTwo77     ~Two() {--count;}
78 };
79 
80 int Two::count = 0;
81 
82 struct Three
83 {
84     static int count;
85     int value;
ThreeThree86     Three(int v, int, int) : value(v) {++count;}
ThreeThree87     Three(Three const & o) : value(o.value) {++count;}
~ThreeThree88     ~Three() {--count;}
89 };
90 
91 int Three::count = 0;
92 
93 template<class T>
94 struct AllocNoConstruct : std::allocator<T>
95 {
96     AllocNoConstruct() = default;
97 
98     template <class T1>
AllocNoConstructAllocNoConstruct99     AllocNoConstruct(AllocNoConstruct<T1>) {}
100 
101     template <class T1>
102     struct rebind {
103         typedef AllocNoConstruct<T1> other;
104     };
105 
constructAllocNoConstruct106     void construct(void*) { assert(false); }
107 };
108 
109 template <class Alloc>
test()110 void test()
111 {
112     int const bad = -1;
113     {
114     std::shared_ptr<Zero> p = std::allocate_shared<Zero>(Alloc());
115     assert(Zero::count == 1);
116     }
117     assert(Zero::count == 0);
118     {
119     int const i = 42;
120     std::shared_ptr<One> p = std::allocate_shared<One>(Alloc(), i);
121     assert(One::count == 1);
122     assert(p->value == i);
123     }
124     assert(One::count == 0);
125     {
126     int const i = 42;
127     std::shared_ptr<Two> p = std::allocate_shared<Two>(Alloc(), i, bad);
128     assert(Two::count == 1);
129     assert(p->value == i);
130     }
131     assert(Two::count == 0);
132     {
133     int const i = 42;
134     std::shared_ptr<Three> p = std::allocate_shared<Three>(Alloc(), i, bad, bad);
135     assert(Three::count == 1);
136     assert(p->value == i);
137     }
138     assert(Three::count == 0);
139 }
140 
main(int,char **)141 int main(int, char**)
142 {
143     test<bare_allocator<void> >();
144     test<test_allocator<void> >();
145 
146     test_allocator_statistics alloc_stats;
147     {
148     int i = 67;
149     char c = 'e';
150     std::shared_ptr<A> p = std::allocate_shared<A>(test_allocator<A>(54, &alloc_stats), i, c);
151     assert(alloc_stats.alloc_count == 1);
152     assert(A::count == 1);
153     assert(p->get_int() == 67);
154     assert(p->get_char() == 'e');
155     }
156     assert(A::count == 0);
157     assert(alloc_stats.alloc_count == 0);
158     {
159     int i = 67;
160     char c = 'e';
161     std::shared_ptr<A> p = std::allocate_shared<A>(min_allocator<void>(), i, c);
162     assert(A::count == 1);
163     assert(p->get_int() == 67);
164     assert(p->get_char() == 'e');
165     }
166     assert(A::count == 0);
167     {
168     int i = 68;
169     char c = 'f';
170     std::shared_ptr<A> p = std::allocate_shared<A>(bare_allocator<void>(), i, c);
171     assert(A::count == 1);
172     assert(p->get_int() == 68);
173     assert(p->get_char() == 'f');
174     }
175     assert(A::count == 0);
176 
177     // Make sure std::allocate_shared handles badly-behaved types properly
178     {
179         std::shared_ptr<operator_hijacker> p1 = std::allocate_shared<operator_hijacker>(min_allocator<operator_hijacker>());
180         std::shared_ptr<operator_hijacker> p2 = std::allocate_shared<operator_hijacker>(min_allocator<operator_hijacker>(), operator_hijacker());
181         assert(p1 != nullptr);
182         assert(p2 != nullptr);
183     }
184 
185     // Test that we don't call construct before C++20.
186 #if TEST_STD_VER < 20
187     {
188     (void)std::allocate_shared<int>(AllocNoConstruct<int>());
189     }
190 #endif // TEST_STD_VER < 20
191 
192   return 0;
193 }
194