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