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, c++20 |
10 | |
11 | // template<class... Args> |
12 | // constexpr T& emplace(Args&&... args) noexcept; |
13 | // Constraints: is_nothrow_constructible_v<T, Args...> is true. |
14 | // |
15 | // Effects: Equivalent to: |
16 | // if (has_value()) { |
17 | // destroy_at(addressof(val)); |
18 | // } else { |
19 | // destroy_at(addressof(unex)); |
20 | // has_val = true; |
21 | // } |
22 | // return *construct_at(addressof(val), std::forward<Args>(args)...); |
23 | |
24 | #include <cassert> |
25 | #include <concepts> |
26 | #include <expected> |
27 | #include <type_traits> |
28 | #include <utility> |
29 | |
30 | #include "../../types.h" |
31 | #include "test_macros.h" |
32 | |
33 | template <class T, class... Args> |
34 | concept CanEmplace = requires(T t, Args&&... args) { t.emplace(std::forward<Args>(args)...); }; |
35 | |
36 | static_assert(CanEmplace<std::expected<int, int>, int>); |
37 | |
38 | template <bool Noexcept> |
39 | struct CtorFromInt { |
40 | CtorFromInt(int) noexcept(Noexcept); |
41 | CtorFromInt(int, int) noexcept(Noexcept); |
42 | }; |
43 | |
44 | static_assert(CanEmplace<std::expected<CtorFromInt<true>, int>, int>); |
45 | static_assert(CanEmplace<std::expected<CtorFromInt<true>, int>, int, int>); |
46 | static_assert(!CanEmplace<std::expected<CtorFromInt<false>, int>, int>); |
47 | static_assert(!CanEmplace<std::expected<CtorFromInt<false>, int>, int, int>); |
48 | |
49 | constexpr bool test() { |
50 | // has_value |
51 | { |
52 | BothNoexcept::state oldState{}; |
53 | BothNoexcept::state newState{}; |
54 | std::expected<BothNoexcept, int> e(std::in_place, oldState, 5); |
55 | decltype(auto) x = e.emplace(newState, 10); |
56 | static_assert(std::same_as<decltype(x), BothNoexcept&>); |
57 | assert(&x == &(*e)); |
58 | |
59 | assert(oldState.dtorCalled); |
60 | assert(e.has_value()); |
61 | assert(e.value().data_ == 10); |
62 | } |
63 | |
64 | // !has_value |
65 | { |
66 | BothMayThrow::state oldState{}; |
67 | std::expected<int, BothMayThrow> e(std::unexpect, oldState, 5); |
68 | decltype(auto) x = e.emplace(10); |
69 | static_assert(std::same_as<decltype(x), int&>); |
70 | assert(&x == &(*e)); |
71 | |
72 | assert(oldState.dtorCalled); |
73 | assert(e.has_value()); |
74 | assert(e.value() == 10); |
75 | } |
76 | |
77 | // TailClobberer |
78 | { |
79 | std::expected<TailClobberer<0>, bool> e(std::unexpect); |
80 | e.emplace(); |
81 | assert(e.has_value()); |
82 | } |
83 | |
84 | // CheckForInvalidWrites |
85 | { |
86 | { |
87 | CheckForInvalidWrites<true> e; |
88 | e.emplace(); |
89 | assert(e.check()); |
90 | } |
91 | { |
92 | CheckForInvalidWrites<false> e; |
93 | e.emplace(); |
94 | assert(e.check()); |
95 | } |
96 | } |
97 | |
98 | return true; |
99 | } |
100 | |
101 | int main(int, char**) { |
102 | test(); |
103 | static_assert(test()); |
104 | return 0; |
105 | } |
106 | |