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