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