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 // GCC has a issue for `Guaranteed copy elision for potentially-overlapping non-static data members`,
12 // please refer to: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108333
13 // XFAIL: gcc-14
14
15 // <expected>
16
17 // template<class F> constexpr auto transform_error(F&& f) &;
18 // template<class F> constexpr auto transform_error(F&& f) const &;
19 // template<class F> constexpr auto transform_error(F&& f) &&;
20 // template<class F> constexpr auto transform_error(F&& f) const &&;
21
22 #include <expected>
23 #include <concepts>
24 #include <cassert>
25 #include <type_traits>
26 #include <utility>
27
28 struct NonCopy {
29 int value;
NonCopyNonCopy30 constexpr explicit NonCopy(int val) : value(val) {}
31 NonCopy(const NonCopy&) = delete;
32 };
33
test_val_types()34 constexpr void test_val_types() {
35 // Test & overload
36 {
37 auto l = [](auto) -> int { return 1; };
38 std::expected<void, int> v(std::unexpected<int>(2));
39 std::same_as<std::expected<void, int>> decltype(auto) val = v.transform_error(l);
40 assert(val.error() == 1);
41 }
42
43 // Test const& overload
44 {
45 auto l = [](auto) -> int { return 1; };
46 const std::expected<void, int> v(std::unexpected<int>(2));
47 std::same_as<std::expected<void, int>> decltype(auto) val = v.transform_error(l);
48 assert(val.error() == 1);
49 }
50
51 // Test && overload
52 {
53 auto l = [](auto) -> int { return 1; };
54 std::expected<void, int> v(std::unexpected<int>(2));
55 std::same_as<std::expected<void, int>> decltype(auto) val = std::move(v).transform_error(l);
56 assert(val.error() == 1);
57 }
58
59 // Test const&& overload
60 {
61 auto l = [](auto) -> int { return 1; };
62 const std::expected<void, int> v(std::unexpected<int>(2));
63 std::same_as<std::expected<void, int>> decltype(auto) val = std::move(v).transform_error(l);
64 assert(val.error() == 1);
65 }
66 }
67
test_fail()68 constexpr void test_fail() {
69 // Test & overload
70 {
71 auto l = [](auto) -> int {
72 assert(false);
73 return 0;
74 };
75 std::expected<void, int> v;
76 std::same_as<std::expected<void, int>> decltype(auto) val = v.transform_error(l);
77 assert(val.has_value());
78 }
79
80 // Test const& overload
81 {
82 auto l = [](auto) -> int {
83 assert(false);
84 return 0;
85 };
86 const std::expected<void, int> v;
87 std::same_as<std::expected<void, int>> decltype(auto) val = v.transform_error(l);
88 assert(val.has_value());
89 }
90
91 // Test && overload
92 {
93 auto l = [](auto) -> int {
94 assert(false);
95 return 0;
96 };
97 std::expected<void, int> v;
98 std::same_as<std::expected<void, int>> decltype(auto) val = std::move(v).transform_error(l);
99 assert(val.has_value());
100 }
101
102 // Test const&& overload
103 {
104 auto l = [](auto) -> int {
105 assert(false);
106 return 0;
107 };
108 const std::expected<void, int> v;
109 std::same_as<std::expected<void, int>> decltype(auto) val = std::move(v).transform_error(l);
110 assert(val.has_value());
111 }
112 }
113
114 // check unex member is direct-non-list-initialized with invoke(std::forward<F>(f))
test_direct_non_list_init()115 constexpr void test_direct_non_list_init() {
116 auto x = [](int i) { return NonCopy(i); };
117 std::expected<void, int> v(std::unexpected<int>(2));
118 std::expected<void, NonCopy> nv = v.transform_error(x);
119 assert(nv.error().value == 2);
120 }
121
test()122 constexpr bool test() {
123 test_fail();
124 test_val_types();
125 test_direct_non_list_init();
126 return true;
127 }
128
main(int,char **)129 int main(int, char**) {
130 test();
131 static_assert(test());
132
133 return 0;
134 }
135