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 // template<class ...Args>
12 // constexpr T& __emplace(Args&& ...);
13
14 #include <ranges>
15
16 #include <cassert>
17 #include <tuple>
18
19 template<int I>
20 struct X {
21 int value = -1;
22 template<int J>
operator ==(X const & a,X<J> const & b)23 friend constexpr bool operator==(X const& a, X<J> const& b) { return I == J && a.value == b.value; }
24 };
25
26 struct NonMovable {
27 int value = -1;
28 NonMovable() = default;
NonMovableNonMovable29 constexpr explicit NonMovable(int v) : value(v) { }
30 NonMovable(NonMovable&&) = delete;
31 NonMovable& operator=(NonMovable&&) = delete;
32 };
33
test()34 constexpr bool test() {
35 {
36 using T = std::tuple<>;
37 using Cache = std::ranges::__non_propagating_cache<T>;
38 Cache cache;
39 T& result = cache.__emplace();
40 assert(&result == &*cache);
41 assert(result == T());
42 }
43
44 {
45 using T = std::tuple<X<0>>;
46 using Cache = std::ranges::__non_propagating_cache<T>;
47 Cache cache;
48 T& result = cache.__emplace();
49 assert(&result == &*cache);
50 assert(result == T());
51 }
52 {
53 using T = std::tuple<X<0>>;
54 using Cache = std::ranges::__non_propagating_cache<T>;
55 Cache cache;
56 T& result = cache.__emplace(X<0>{0});
57 assert(&result == &*cache);
58 assert(result == T(X<0>{0}));
59 }
60
61 {
62 using T = std::tuple<X<0>, X<1>>;
63 using Cache = std::ranges::__non_propagating_cache<T>;
64 Cache cache;
65 T& result = cache.__emplace();
66 assert(&result == &*cache);
67 assert(result == T());
68 }
69 {
70 using T = std::tuple<X<0>, X<1>>;
71 using Cache = std::ranges::__non_propagating_cache<T>;
72 Cache cache;
73 T& result = cache.__emplace(X<0>{0}, X<1>{1});
74 assert(&result == &*cache);
75 assert(result == T(X<0>{0}, X<1>{1}));
76 }
77
78 // Make sure that we do not require the type to be movable when we emplace it.
79 // Move elision should be performed instead, see http://eel.is/c++draft/range.nonprop.cache#note-1.
80 {
81 using Cache = std::ranges::__non_propagating_cache<NonMovable>;
82 Cache cache;
83 NonMovable& result = cache.__emplace();
84 assert(&result == &*cache);
85 assert(result.value == -1);
86 }
87
88 return true;
89 }
90
main(int,char **)91 int main(int, char**) {
92 static_assert(test());
93 test();
94 return 0;
95 }
96