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 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
11
12 // <memory>
13 //
14 // namespace ranges {
15 // template<class T, class... Args>
16 // constexpr T* construct_at(T* location, Args&&... args); // since C++20
17 // }
18
19 #include <cassert>
20 #include <initializer_list>
21 #include <memory>
22 #include <type_traits>
23
24 #include "test_iterators.h"
25 #include "test_macros.h"
26
27 // TODO(varconst): consolidate the ADL checks into a single file.
28 // Because this is a variable and not a function, it's guaranteed that ADL won't be used. However,
29 // implementations are allowed to use a different mechanism to achieve this effect, so this check is
30 // libc++-specific.
31 LIBCPP_STATIC_ASSERT(std::is_class_v<decltype(std::ranges::construct_at)>);
32
33 struct Foo {
34 int x = 0;
35 int y = 0;
36
37 constexpr Foo() = default;
FooFoo38 constexpr explicit Foo(int set_x, int set_y) : x(set_x), y(set_y) {}
39 constexpr Foo(std::initializer_list<int>);
40
41 void operator&() const = delete;
42 void operator,(auto&&) const = delete;
43 };
44
45 ASSERT_SAME_TYPE(decltype(std::ranges::construct_at((int*)nullptr)), int*);
46 ASSERT_SAME_TYPE(decltype(std::ranges::construct_at((Foo*)nullptr)), Foo*);
47
48 struct Counted {
49 int& count;
50
CountedCounted51 constexpr Counted(int& count_ref) : count(count_ref) { ++count; }
CountedCounted52 constexpr Counted(const Counted& rhs) : count(rhs.count) { ++count; }
~CountedCounted53 constexpr ~Counted() { --count; }
54 };
55
test()56 constexpr bool test() {
57 // Value initialization.
58 {
59 int x = 1;
60
61 int* result = std::ranges::construct_at(&x);
62 assert(result == &x);
63 assert(x == 0);
64 }
65
66 // Copy initialization.
67 {
68 int x = 1;
69
70 int* result = std::ranges::construct_at(&x, 42);
71 assert(result == &x);
72 assert(x == 42);
73 }
74
75 // Explicit multiargument constructor; also checks that the initializer list constructor is not invoked.
76 {
77 Foo f;
78
79 Foo* result = std::ranges::construct_at(std::addressof(f), 42, 123);
80 assert(result == std::addressof(f));
81 assert(f.x == 42);
82 assert(f.y == 123);
83 }
84
85 // Works with buffers of uninitialized memory.
86 {
87 std::allocator<Counted> alloc;
88 Counted* out = alloc.allocate(2);
89 int count = 0;
90
91 Counted* result = std::ranges::construct_at(out, count);
92 assert(result == out);
93 assert(count == 1);
94
95 result = std::ranges::construct_at(out + 1, count);
96 assert(result == out + 1);
97 assert(count == 2);
98
99 std::destroy(out, out + 1);
100 alloc.deallocate(out, 2);
101 }
102
103 // Works with const pointers.
104 {
105 int x = 1;
106 const int* ptr = &x;
107
108 const int* result = std::ranges::construct_at(ptr, 42);
109 assert(result == ptr);
110 assert(x == 42);
111 }
112
113 return true;
114 }
115
can_construct_at(auto &&...args)116 constexpr bool can_construct_at(auto&&... args)
117 requires requires { std::ranges::construct_at(decltype(args)(args)...); }
118 { return true; }
119
can_construct_at(auto &&...)120 constexpr bool can_construct_at(auto&&...) { return false; }
121
122 // Check that SFINAE works.
123 static_assert( can_construct_at((Foo*)nullptr, 1, 2));
124 static_assert(!can_construct_at((Foo*)nullptr, 1));
125 static_assert(!can_construct_at((Foo*)nullptr, 1, 2, 3));
126 static_assert(!can_construct_at(nullptr, 1, 2));
127 static_assert(!can_construct_at((int*)nullptr, 1, 2));
128 static_assert(!can_construct_at(contiguous_iterator<Foo*>(), 1, 2));
129 // Can't construct function pointers.
130 static_assert(!can_construct_at((int(*)())nullptr));
131 static_assert(!can_construct_at((int(*)())nullptr, nullptr));
132 // TODO(varconst): check that array types work once D114649 implementing LWG3639 lands.
133
main(int,char **)134 int main(int, char**) {
135 test();
136 static_assert(test());
137
138 return 0;
139 }
140