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