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 // Throwing bad_optional_access is supported starting in macosx10.13
12 // XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions
13 
14 // <optional>
15 
16 // template<class F> constexpr auto transform(F&&) &;
17 // template<class F> constexpr auto transform(F&&) &&;
18 // template<class F> constexpr auto transform(F&&) const&;
19 // template<class F> constexpr auto transform(F&&) const&&;
20 
21 #include "test_macros.h"
22 #include <cassert>
23 #include <optional>
24 #include <type_traits>
25 
26 struct LVal {
27   constexpr int operator()(int&) { return 1; }
28   int operator()(const int&) = delete;
29   int operator()(int&&) = delete;
30   int operator()(const int&&) = delete;
31 };
32 
33 struct CLVal {
34   int operator()(int&) = delete;
35   constexpr int operator()(const int&) { return 1; }
36   int operator()(int&&) = delete;
37   int operator()(const int&&) = delete;
38 };
39 
40 struct RVal {
41   int operator()(int&) = delete;
42   int operator()(const int&) = delete;
43   constexpr int operator()(int&&) { return 1; }
44   int operator()(const int&&) = delete;
45 };
46 
47 struct CRVal {
48   int operator()(int&) = delete;
49   int operator()(const int&) = delete;
50   int operator()(int&&) = delete;
51   constexpr int operator()(const int&&) { return 1; }
52 };
53 
54 struct RefQual {
55   constexpr int operator()(int) & { return 1; }
56   int operator()(int) const& = delete;
57   int operator()(int) && = delete;
58   int operator()(int) const&& = delete;
59 };
60 
61 struct CRefQual {
62   int operator()(int) & = delete;
63   constexpr int operator()(int) const& { return 1; }
64   int operator()(int) && = delete;
65   int operator()(int) const&& = delete;
66 };
67 
68 struct RVRefQual {
69   int operator()(int) & = delete;
70   int operator()(int) const& = delete;
71   constexpr int operator()(int) && { return 1; }
72   int operator()(int) const&& = delete;
73 };
74 
75 struct RVCRefQual {
76   int operator()(int) & = delete;
77   int operator()(int) const& = delete;
78   int operator()(int) && = delete;
79   constexpr int operator()(int) const&& { return 1; }
80 };
81 
82 struct NoCopy {
83   NoCopy() = default;
84   NoCopy(const NoCopy&) { assert(false); }
85   int operator()(const NoCopy&&) { return 1; }
86 };
87 
88 struct NoMove {
89   NoMove() = default;
90   NoMove(NoMove&&) = delete;
91   NoMove operator()(const NoCopy&&) { return NoMove{}; }
92 };
93 
94 constexpr void test_val_types() {
95   // Test & overload
96   {
97     // Without & qualifier on F's operator()
98     {
99       std::optional<int> i{0};
100       assert(i.transform(LVal{}) == 1);
101       ASSERT_SAME_TYPE(decltype(i.transform(LVal{})), std::optional<int>);
102     }
103 
104     //With & qualifier on F's operator()
105     {
106       std::optional<int> i{0};
107       RefQual l{};
108       assert(i.transform(l) == 1);
109       ASSERT_SAME_TYPE(decltype(i.transform(l)), std::optional<int>);
110     }
111   }
112 
113   // Test const& overload
114   {
115     // Without & qualifier on F's operator()
116     {
117       const std::optional<int> i{0};
118       assert(i.transform(CLVal{}) == 1);
119       ASSERT_SAME_TYPE(decltype(i.transform(CLVal{})), std::optional<int>);
120     }
121 
122     //With & qualifier on F's operator()
123     {
124       const std::optional<int> i{0};
125       const CRefQual l{};
126       assert(i.transform(l) == 1);
127       ASSERT_SAME_TYPE(decltype(i.transform(l)), std::optional<int>);
128     }
129   }
130 
131   // Test && overload
132   {
133     // Without & qualifier on F's operator()
134     {
135       std::optional<int> i{0};
136       assert(std::move(i).transform(RVal{}) == 1);
137       ASSERT_SAME_TYPE(decltype(std::move(i).transform(RVal{})), std::optional<int>);
138     }
139 
140     //With & qualifier on F's operator()
141     {
142       std::optional<int> i{0};
143       assert(i.transform(RVRefQual{}) == 1);
144       ASSERT_SAME_TYPE(decltype(i.transform(RVRefQual{})), std::optional<int>);
145     }
146   }
147 
148   // Test const&& overload
149   {
150     // Without & qualifier on F's operator()
151     {
152       const std::optional<int> i{0};
153       assert(std::move(i).transform(CRVal{}) == 1);
154       ASSERT_SAME_TYPE(decltype(std::move(i).transform(CRVal{})), std::optional<int>);
155     }
156 
157     //With & qualifier on F's operator()
158     {
159       const std::optional<int> i{0};
160       const RVCRefQual l{};
161       assert(i.transform(std::move(l)) == 1);
162       ASSERT_SAME_TYPE(decltype(i.transform(std::move(l))), std::optional<int>);
163     }
164   }
165 }
166 
167 struct NonConst {
168   int non_const() { return 1; }
169 };
170 
171 // check that the lambda body is not instantiated during overload resolution
172 constexpr void test_sfinae() {
173   std::optional<NonConst> opt{};
174   auto l = [](auto&& x) { return x.non_const(); };
175   opt.transform(l);
176   std::move(opt).transform(l);
177 }
178 
179 constexpr bool test() {
180   test_sfinae();
181   test_val_types();
182   std::optional<int> opt;
183   const auto& copt = opt;
184 
185   const auto never_called = [](int) {
186     assert(false);
187     return 0;
188   };
189 
190   opt.transform(never_called);
191   std::move(opt).transform(never_called);
192   copt.transform(never_called);
193   std::move(copt).transform(never_called);
194 
195   std::optional<NoCopy> nc;
196   const auto& cnc = nc;
197   std::move(nc).transform(NoCopy{});
198   std::move(cnc).transform(NoCopy{});
199 
200   std::move(nc).transform(NoMove{});
201   std::move(cnc).transform(NoMove{});
202 
203   return true;
204 }
205 
206 int main(int, char**) {
207   test();
208   static_assert(test());
209   return 0;
210 }
211