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, c++17
10 
11 // <memory>
12 
13 // template <class T, class ...Args>
14 // constexpr T* construct_at(T* location, Args&& ...args);
15 
16 #include <memory>
17 #include <cassert>
18 #include <utility>
19 
20 #include "test_iterators.h"
21 
22 struct Foo {
FooFoo23     constexpr Foo() { }
FooFoo24     constexpr Foo(int a, char b, double c) : a_(a), b_(b), c_(c) { }
FooFoo25     constexpr Foo(int a, char b, double c, int* count) : Foo(a, b, c) { *count += 1; }
operator ==Foo26     constexpr bool operator==(Foo const& other) const {
27         return a_ == other.a_ && b_ == other.b_ && c_ == other.c_;
28     }
29 
30 private:
31     int a_;
32     char b_;
33     double c_;
34 };
35 
36 struct Counted {
37     int& count_;
CountedCounted38     constexpr Counted(int& count) : count_(count) { ++count; }
CountedCounted39     constexpr Counted(Counted const& that) : count_(that.count_) { ++count_; }
~CountedCounted40     constexpr ~Counted() { --count_; }
41 };
42 
test()43 constexpr bool test()
44 {
45     {
46         int i = 99;
47         int* res = std::construct_at(&i);
48         assert(res == &i);
49         assert(*res == 0);
50     }
51 
52     {
53         int i = 0;
54         int* res = std::construct_at(&i, 42);
55         assert(res == &i);
56         assert(*res == 42);
57     }
58 
59     {
60         Foo foo = {};
61         int count = 0;
62         Foo* res = std::construct_at(&foo, 42, 'x', 123.89, &count);
63         assert(res == &foo);
64         assert(*res == Foo(42, 'x', 123.89));
65         assert(count == 1);
66     }
67 
68     {
69         std::allocator<Counted> a;
70         Counted* p = a.allocate(2);
71         int count = 0;
72         std::construct_at(p, count);
73         assert(count == 1);
74         std::construct_at(p+1, count);
75         assert(count == 2);
76         (p+1)->~Counted();
77         assert(count == 1);
78         p->~Counted();
79         assert(count == 0);
80         a.deallocate(p, 2);
81     }
82 
83     {
84         std::allocator<Counted const> a;
85         Counted const* p = a.allocate(2);
86         int count = 0;
87         std::construct_at(p, count);
88         assert(count == 1);
89         std::construct_at(p+1, count);
90         assert(count == 2);
91         (p+1)->~Counted();
92         assert(count == 1);
93         p->~Counted();
94         assert(count == 0);
95         a.deallocate(p, 2);
96     }
97 
98     return true;
99 }
100 
101 template <class ...Args, class = decltype(std::construct_at(std::declval<Args>()...))>
can_construct_at(Args &&...)102 constexpr bool can_construct_at(Args&&...) { return true; }
103 
104 template <class ...Args>
can_construct_at(...)105 constexpr bool can_construct_at(...) { return false; }
106 
107 // Check that SFINAE works.
108 static_assert( can_construct_at((int*)nullptr, 42));
109 static_assert( can_construct_at((Foo*)nullptr, 1, '2', 3.0));
110 static_assert(!can_construct_at((Foo*)nullptr, 1, '2'));
111 static_assert(!can_construct_at((Foo*)nullptr, 1, '2', 3.0, 4));
112 static_assert(!can_construct_at(nullptr, 1, '2', 3.0));
113 static_assert(!can_construct_at((int*)nullptr, 1, '2', 3.0));
114 static_assert(!can_construct_at(contiguous_iterator<Foo*>(), 1, '2', 3.0));
115 // Can't construct function pointers.
116 static_assert(!can_construct_at((int(*)())nullptr));
117 static_assert(!can_construct_at((int(*)())nullptr, nullptr));
118 
main(int,char **)119 int main(int, char**)
120 {
121     test();
122     static_assert(test());
123     return 0;
124 }
125