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 // UNSUPPORTED: clang-8
10 // constexpr destructors are only supported starting with gcc 10
11 // UNSUPPORTED: gcc-8, gcc-9
12
13 // <memory>
14
15 // template <class Alloc>
16 // struct allocator_traits
17 // {
18 // template <class Ptr>
19 // static constexpr void destroy(allocator_type& a, Ptr p);
20 // ...
21 // };
22
23 #include <memory>
24 #include <cassert>
25 #include <cstddef>
26
27 #include "test_macros.h"
28 #include "incomplete_type_helper.h"
29
30 template <class T>
31 struct NoDestroy
32 {
33 typedef T value_type;
34
allocateNoDestroy35 TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n)
36 {
37 return std::allocator<T>().allocate(n);
38 }
39
deallocateNoDestroy40 TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n)
41 {
42 return std::allocator<T>().deallocate(p, n);
43 }
44 };
45
46 template <class T>
47 struct CountDestroy
48 {
CountDestroyCountDestroy49 TEST_CONSTEXPR explicit CountDestroy(int* counter)
50 : counter_(counter)
51 { }
52
53 typedef T value_type;
54
allocateCountDestroy55 TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n)
56 {
57 return std::allocator<T>().allocate(n);
58 }
59
deallocateCountDestroy60 TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n)
61 {
62 return std::allocator<T>().deallocate(p, n);
63 }
64
65 template <class U>
destroyCountDestroy66 TEST_CONSTEXPR_CXX20 void destroy(U* p)
67 {
68 ++*counter_;
69 p->~U();
70 }
71
72 int* counter_;
73 };
74
75 struct CountDestructor
76 {
CountDestructorCountDestructor77 TEST_CONSTEXPR explicit CountDestructor(int* counter)
78 : counter_(counter)
79 { }
80
~CountDestructorCountDestructor81 TEST_CONSTEXPR_CXX20 ~CountDestructor() { ++*counter_; }
82
83 int* counter_;
84 };
85
test()86 TEST_CONSTEXPR_CXX20 bool test()
87 {
88 {
89 typedef NoDestroy<CountDestructor> Alloc;
90 int destructors = 0;
91 Alloc alloc;
92 CountDestructor* pool = std::allocator_traits<Alloc>::allocate(alloc, 1);
93
94 std::allocator_traits<Alloc>::construct(alloc, pool, &destructors);
95 assert(destructors == 0);
96
97 std::allocator_traits<Alloc>::destroy(alloc, pool);
98 assert(destructors == 1);
99
100 std::allocator_traits<Alloc>::deallocate(alloc, pool, 1);
101 }
102 {
103 typedef IncompleteHolder* T;
104 typedef NoDestroy<T> Alloc;
105 Alloc alloc;
106 T* pool = std::allocator_traits<Alloc>::allocate(alloc, 1);
107 std::allocator_traits<Alloc>::construct(alloc, pool, nullptr);
108 std::allocator_traits<Alloc>::destroy(alloc, pool);
109 std::allocator_traits<Alloc>::deallocate(alloc, pool, 1);
110 }
111 {
112 typedef CountDestroy<CountDestructor> Alloc;
113 int destroys_called = 0;
114 int destructors_called = 0;
115 Alloc alloc(&destroys_called);
116
117 CountDestructor* pool = std::allocator_traits<Alloc>::allocate(alloc, 1);
118 std::allocator_traits<Alloc>::construct(alloc, pool, &destructors_called);
119 assert(destroys_called == 0);
120 assert(destructors_called == 0);
121
122 std::allocator_traits<Alloc>::destroy(alloc, pool);
123 assert(destroys_called == 1);
124 assert(destructors_called == 1);
125
126 std::allocator_traits<Alloc>::deallocate(alloc, pool, 1);
127 }
128 return true;
129 }
130
main(int,char **)131 int main(int, char**)
132 {
133 test();
134 #if TEST_STD_VER > 17
135 static_assert(test());
136 #endif
137 return 0;
138 }
139