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: c++03, c++11, c++14
10 
11 // <memory>
12 
13 // template <class T>
14 // constexpr void destroy_at(T*);
15 
16 #include <memory>
17 #include <cassert>
18 #include <type_traits>
19 
20 #include "test_macros.h"
21 
22 struct Counted {
23     int* counter_;
CountedCounted24     TEST_CONSTEXPR Counted(int* counter) : counter_(counter) { ++*counter_; }
~CountedCounted25     TEST_CONSTEXPR_CXX20 ~Counted() { --*counter_; }
26     friend void operator&(Counted) = delete;
27 };
28 
29 struct VirtualCounted {
30     int* counter_;
VirtualCountedVirtualCounted31     TEST_CONSTEXPR VirtualCounted(int* counter) : counter_(counter) { ++*counter_; }
~VirtualCountedVirtualCounted32     TEST_CONSTEXPR_CXX20 virtual ~VirtualCounted() { --*counter_; }
33     void operator&() const = delete;
34 };
35 
36 struct DerivedCounted : VirtualCounted {
DerivedCountedDerivedCounted37     TEST_CONSTEXPR DerivedCounted(int* counter) : VirtualCounted(counter) { }
~DerivedCountedDerivedCounted38     TEST_CONSTEXPR_CXX20 ~DerivedCounted() override { }
39 };
40 
41 #if TEST_STD_VER > 17
test_arrays()42 constexpr bool test_arrays() {
43     {
44         using Array = Counted[3];
45         using Alloc = std::allocator<Array>;
46         Alloc alloc;
47         Array* ptr = std::allocator_traits<Alloc>::allocate(alloc, 1);
48         Array& arr = *ptr;
49 
50         int counter = 0;
51         for (int i = 0; i != 3; ++i)
52             std::allocator_traits<Alloc>::construct(alloc, std::addressof(arr[i]), &counter);
53         assert(counter == 3);
54 
55         std::destroy_at(ptr);
56         ASSERT_SAME_TYPE(decltype(std::destroy_at(ptr)), void);
57         assert(counter == 0);
58 
59         std::allocator_traits<Alloc>::deallocate(alloc, ptr, 1);
60     }
61     {
62         using Array = Counted[3][2];
63         using Alloc = std::allocator<Array>;
64         Alloc alloc;
65         Array* ptr = std::allocator_traits<Alloc>::allocate(alloc, 1);
66         Array& arr = *ptr;
67 
68         int counter = 0;
69         for (int i = 0; i != 3; ++i)
70             for (int j = 0; j != 2; ++j)
71                 std::allocator_traits<Alloc>::construct(alloc, std::addressof(arr[i][j]), &counter);
72         assert(counter == 3 * 2);
73 
74         std::destroy_at(ptr);
75         ASSERT_SAME_TYPE(decltype(std::destroy_at(ptr)), void);
76         assert(counter == 0);
77 
78         std::allocator_traits<Alloc>::deallocate(alloc, ptr, 1);
79     }
80     return true;
81 }
82 #endif
83 
test()84 TEST_CONSTEXPR_CXX20 bool test() {
85     {
86         using Alloc = std::allocator<Counted>;
87         Alloc alloc;
88         Counted* ptr1 = std::allocator_traits<Alloc>::allocate(alloc, 1);
89         Counted* ptr2 = std::allocator_traits<Alloc>::allocate(alloc, 1);
90 
91         int counter = 0;
92         std::allocator_traits<Alloc>::construct(alloc, ptr1, &counter);
93         std::allocator_traits<Alloc>::construct(alloc, ptr2, &counter);
94         assert(counter == 2);
95 
96         std::destroy_at(ptr1);
97         ASSERT_SAME_TYPE(decltype(std::destroy_at(ptr1)), void);
98         assert(counter == 1);
99 
100         std::destroy_at(ptr2);
101         assert(counter == 0);
102 
103         std::allocator_traits<Alloc>::deallocate(alloc, ptr1, 1);
104         std::allocator_traits<Alloc>::deallocate(alloc, ptr2, 1);
105     }
106     {
107         using Alloc = std::allocator<DerivedCounted>;
108         Alloc alloc;
109         DerivedCounted* ptr1 = std::allocator_traits<Alloc>::allocate(alloc, 1);
110         DerivedCounted* ptr2 = std::allocator_traits<Alloc>::allocate(alloc, 1);
111 
112         int counter = 0;
113         std::allocator_traits<Alloc>::construct(alloc, ptr1, &counter);
114         std::allocator_traits<Alloc>::construct(alloc, ptr2, &counter);
115         assert(counter == 2);
116 
117         std::destroy_at(ptr1);
118         ASSERT_SAME_TYPE(decltype(std::destroy_at(ptr1)), void);
119         assert(counter == 1);
120 
121         std::destroy_at(ptr2);
122         assert(counter == 0);
123 
124         std::allocator_traits<Alloc>::deallocate(alloc, ptr1, 1);
125         std::allocator_traits<Alloc>::deallocate(alloc, ptr2, 1);
126     }
127 
128     return true;
129 }
130 
main(int,char **)131 int main(int, char**) {
132     test();
133 #if TEST_STD_VER > 17
134     test_arrays();
135     static_assert(test());
136     // TODO: Until std::construct_at has support for arrays, it's impossible to test this
137     //       in a constexpr context (see https://reviews.llvm.org/D114903).
138     // static_assert(test_arrays());
139 #endif
140     return 0;
141 }
142