xref: /llvm-project/libcxx/test/std/utilities/expected/expected.unexpected/ctor/ctor.error.pass.cpp (revision 6a54dfbfe534276d644d7f9c027f0deeb748dd53)
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 Err = E>
12 //   constexpr explicit unexpected(Err&& e);
13 //
14 // Constraints:
15 // - is_same_v<remove_cvref_t<Err>, unexpected> is false; and
16 // - is_same_v<remove_cvref_t<Err>, in_place_t> is false; and
17 // - is_constructible_v<E, Err> is true.
18 //
19 // Effects: Direct-non-list-initializes unex with std::forward<Err>(e).
20 // Throws: Any exception thrown by the initialization of unex.
21 
22 #include <cassert>
23 #include <concepts>
24 #include <expected>
25 #include <utility>
26 
27 #include "test_macros.h"
28 
29 // Test Constraints:
30 static_assert(std::constructible_from<std::unexpected<int>, int>);
31 
32 // is_same_v<remove_cvref_t<Err>, unexpected>
33 struct CstrFromUnexpected {
34   CstrFromUnexpected(CstrFromUnexpected const&) = delete;
35   CstrFromUnexpected(std::unexpected<CstrFromUnexpected> const&);
36 };
37 static_assert(!std::constructible_from<std::unexpected<CstrFromUnexpected>, std::unexpected<CstrFromUnexpected>>);
38 
39 // is_same_v<remove_cvref_t<Err>, in_place_t>
40 struct CstrFromInplace {
41   CstrFromInplace(std::in_place_t);
42 };
43 static_assert(!std::constructible_from<std::unexpected<CstrFromInplace>, std::in_place_t>);
44 
45 // !is_constructible_v<E, Err>
46 struct Foo {};
47 static_assert(!std::constructible_from<std::unexpected<Foo>, int>);
48 
49 // test explicit
50 static_assert(std::convertible_to<int, int>);
51 static_assert(!std::convertible_to<int, std::unexpected<int>>);
52 
53 struct Error {
54   int i;
55   constexpr Error(int ii) : i(ii) {}
56   constexpr Error(const Error& other) : i(other.i) {}
57   constexpr Error(Error&& other) : i(other.i) { other.i = 0; }
58   Error(std::initializer_list<Error>) { assert(false); }
59 };
60 
61 constexpr bool test() {
62   // lvalue
63   {
64     Error e(5);
65     std::unexpected<Error> unex(e);
66     assert(unex.error().i == 5);
67     assert(e.i == 5);
68   }
69 
70   // rvalue
71   {
72     Error e(5);
73     std::unexpected<Error> unex(std::move(e));
74     assert(unex.error().i == 5);
75     assert(e.i == 0);
76   }
77 
78   // Direct-non-list-initializes: does not trigger initializer_list overload
79   {
80     Error e(5);
81     [[maybe_unused]] std::unexpected<Error> unex(e);
82   }
83 
84   // Test default template argument.
85   // Without it, the template parameter cannot be deduced from an initializer list
86   {
87     struct Bar {
88       int i;
89       int j;
90       constexpr Bar(int ii, int jj) : i(ii), j(jj) {}
91     };
92     std::unexpected<Bar> ue({5, 6});
93     assert(ue.error().i == 5);
94     assert(ue.error().j == 6);
95   }
96 
97   return true;
98 }
99 
100 void testException() {
101 #ifndef TEST_HAS_NO_EXCEPTIONS
102   struct Except {};
103 
104   struct Throwing {
105     Throwing() = default;
106     Throwing(const Throwing&) { throw Except{}; }
107   };
108 
109   Throwing t;
110   try {
111     std::unexpected<Throwing> u(t);
112     assert(false);
113   } catch (Except) {
114   }
115 #endif // TEST_HAS_NO_EXCEPTIONS
116 }
117 
118 int main(int, char**) {
119   test();
120   static_assert(test());
121   testException();
122   return 0;
123 }
124