xref: /llvm-project/libcxx/test/std/utilities/meta/meta.rel/is_nothrow_invocable.pass.cpp (revision e99c4906e44ae3f921fa05356909d006cda8d954)
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
10 
11 // type_traits
12 
13 // is_nothrow_invocable
14 
15 #include <cstddef>
16 #include <type_traits>
17 #include <vector>
18 
19 struct Tag {};
20 
21 struct Implicit {
22   Implicit(int) noexcept {}
23 };
24 
25 struct ThrowsImplicit {
26   ThrowsImplicit(int) {}
27 };
28 
29 struct Explicit {
30   explicit Explicit(int) noexcept {}
31 };
32 
33 template <bool IsNoexcept, class Ret, class... Args>
34 struct CallObject {
35   Ret operator()(Args&&...) const noexcept(IsNoexcept);
36 };
37 
38 struct Sink {
39   template <class... Args>
40   void operator()(Args&&...) const noexcept {}
41 };
42 
43 template <class Fn, class... Args>
44 constexpr bool throws_invocable() {
45   return std::is_invocable<Fn, Args...>::value &&
46          !std::is_nothrow_invocable<Fn, Args...>::value;
47 }
48 
49 template <class Ret, class Fn, class... Args>
50 constexpr bool throws_invocable_r() {
51   return std::is_invocable_r<Ret, Fn, Args...>::value &&
52          !std::is_nothrow_invocable_r<Ret, Fn, Args...>::value;
53 }
54 
55 void test_noexcept_function_pointers() {
56   struct Dummy {
57     void foo() noexcept {}
58     static void bar() noexcept {}
59   };
60   // Check that PMF's and function pointers actually work and that
61   // is_nothrow_invocable returns true for noexcept PMF's and function
62   // pointers.
63   static_assert(std::is_nothrow_invocable<decltype(&Dummy::foo), Dummy&>::value, "");
64   static_assert(std::is_nothrow_invocable<decltype(&Dummy::bar)>::value, "");
65 }
66 
67 int main(int, char**) {
68   using AbominableFunc = void(...) const noexcept;
69   //  Non-callable things
70   {
71     static_assert(!std::is_nothrow_invocable<void>::value, "");
72     static_assert(!std::is_nothrow_invocable<const void>::value, "");
73     static_assert(!std::is_nothrow_invocable<volatile void>::value, "");
74     static_assert(!std::is_nothrow_invocable<const volatile void>::value, "");
75     static_assert(!std::is_nothrow_invocable<std::nullptr_t>::value, "");
76     static_assert(!std::is_nothrow_invocable<int>::value, "");
77     static_assert(!std::is_nothrow_invocable<double>::value, "");
78 
79     static_assert(!std::is_nothrow_invocable<int[]>::value, "");
80     static_assert(!std::is_nothrow_invocable<int[3]>::value, "");
81 
82     static_assert(!std::is_nothrow_invocable<int*>::value, "");
83     static_assert(!std::is_nothrow_invocable<const int*>::value, "");
84     static_assert(!std::is_nothrow_invocable<int const*>::value, "");
85 
86     static_assert(!std::is_nothrow_invocable<int&>::value, "");
87     static_assert(!std::is_nothrow_invocable<const int&>::value, "");
88     static_assert(!std::is_nothrow_invocable<int&&>::value, "");
89 
90     static_assert(!std::is_nothrow_invocable<int, std::vector<int> >::value,
91                   "");
92     static_assert(!std::is_nothrow_invocable<int, std::vector<int*> >::value,
93                   "");
94     static_assert(!std::is_nothrow_invocable<int, std::vector<int**> >::value,
95                   "");
96 
97     static_assert(!std::is_nothrow_invocable<AbominableFunc>::value, "");
98 
99     //  with parameters
100     static_assert(!std::is_nothrow_invocable<int, int>::value, "");
101     static_assert(!std::is_nothrow_invocable<int, double, float>::value, "");
102     static_assert(!std::is_nothrow_invocable<int, char, float, double>::value,
103                   "");
104     static_assert(!std::is_nothrow_invocable<Sink, AbominableFunc>::value, "");
105     static_assert(!std::is_nothrow_invocable<Sink, void>::value, "");
106     static_assert(!std::is_nothrow_invocable<Sink, const volatile void>::value,
107                   "");
108 
109     static_assert(!std::is_nothrow_invocable_r<int, void>::value, "");
110     static_assert(!std::is_nothrow_invocable_r<int, const void>::value, "");
111     static_assert(!std::is_nothrow_invocable_r<int, volatile void>::value, "");
112     static_assert(!std::is_nothrow_invocable_r<int, const volatile void>::value,
113                   "");
114     static_assert(!std::is_nothrow_invocable_r<int, std::nullptr_t>::value, "");
115     static_assert(!std::is_nothrow_invocable_r<int, int>::value, "");
116     static_assert(!std::is_nothrow_invocable_r<int, double>::value, "");
117 
118     static_assert(!std::is_nothrow_invocable_r<int, int[]>::value, "");
119     static_assert(!std::is_nothrow_invocable_r<int, int[3]>::value, "");
120 
121     static_assert(!std::is_nothrow_invocable_r<int, int*>::value, "");
122     static_assert(!std::is_nothrow_invocable_r<int, const int*>::value, "");
123     static_assert(!std::is_nothrow_invocable_r<int, int const*>::value, "");
124 
125     static_assert(!std::is_nothrow_invocable_r<int, int&>::value, "");
126     static_assert(!std::is_nothrow_invocable_r<int, const int&>::value, "");
127     static_assert(!std::is_nothrow_invocable_r<int, int&&>::value, "");
128 
129     static_assert(!std::is_nothrow_invocable_r<int, std::vector<int> >::value,
130                   "");
131     static_assert(!std::is_nothrow_invocable_r<int, std::vector<int*> >::value,
132                   "");
133     static_assert(!std::is_nothrow_invocable_r<int, std::vector<int**> >::value,
134                   "");
135     static_assert(!std::is_nothrow_invocable_r<void, AbominableFunc>::value,
136                   "");
137 
138     //  with parameters
139     static_assert(!std::is_nothrow_invocable_r<int, int, int>::value, "");
140     static_assert(!std::is_nothrow_invocable_r<int, int, double, float>::value,
141                   "");
142     static_assert(
143         !std::is_nothrow_invocable_r<int, int, char, float, double>::value, "");
144     static_assert(
145         !std::is_nothrow_invocable_r<void, Sink, AbominableFunc>::value, "");
146     static_assert(!std::is_nothrow_invocable_r<void, Sink, void>::value, "");
147     static_assert(
148         !std::is_nothrow_invocable_r<void, Sink, const volatile void>::value,
149         "");
150   }
151 
152   {
153     // Check that the conversion to the return type is properly checked
154     using Fn = CallObject<true, int>;
155     static_assert(std::is_nothrow_invocable_r<Implicit, Fn>::value, "");
156     static_assert(std::is_nothrow_invocable_r<double, Fn>::value, "");
157     static_assert(std::is_nothrow_invocable_r<const volatile void, Fn>::value,
158                   "");
159     static_assert(throws_invocable_r<ThrowsImplicit, Fn>(), "");
160     static_assert(!std::is_nothrow_invocable<Fn(), Explicit>(), "");
161   }
162   {
163     // Check that the conversion to the parameters is properly checked
164     using Fn = CallObject<true, void, const Implicit&, const ThrowsImplicit&>;
165     static_assert(
166         std::is_nothrow_invocable<Fn, Implicit&, ThrowsImplicit&>::value, "");
167     static_assert(std::is_nothrow_invocable<Fn, int, ThrowsImplicit&>::value,
168                   "");
169     static_assert(throws_invocable<Fn, int, int>(), "");
170     static_assert(!std::is_nothrow_invocable<Fn>::value, "");
171   }
172   {
173     // Check that the noexcept-ness of function objects is checked.
174     using Fn = CallObject<true, void>;
175     using Fn2 = CallObject<false, void>;
176     static_assert(std::is_nothrow_invocable<Fn>::value, "");
177     static_assert(throws_invocable<Fn2>(), "");
178   }
179   {
180     // Check that PMD derefs are noexcept
181     using Fn = int(Tag::*);
182     static_assert(std::is_nothrow_invocable<Fn, Tag&>::value, "");
183     static_assert(std::is_nothrow_invocable_r<Implicit, Fn, Tag&>::value, "");
184     static_assert(throws_invocable_r<ThrowsImplicit, Fn, Tag&>(), "");
185   }
186   {
187     // Check that it's fine if the result type is non-moveable.
188     struct CantMove {
189       CantMove() = default;
190       CantMove(CantMove&&) = delete;
191     };
192 
193     static_assert(!std::is_move_constructible_v<CantMove>);
194     static_assert(!std::is_copy_constructible_v<CantMove>);
195 
196     using Fn = CantMove() noexcept;
197 
198     static_assert(std::is_nothrow_invocable_r<CantMove, Fn>::value);
199     static_assert(!std::is_nothrow_invocable_r<CantMove, Fn, int>::value);
200 
201     static_assert(std::is_nothrow_invocable_r_v<CantMove, Fn>);
202     static_assert(!std::is_nothrow_invocable_r_v<CantMove, Fn, int>);
203   }
204   {
205     // Check for is_nothrow_invocable_v
206     using Fn = CallObject<true, int>;
207     static_assert(std::is_nothrow_invocable_v<Fn>, "");
208     static_assert(!std::is_nothrow_invocable_v<Fn, int>, "");
209   }
210   {
211     // Check for is_nothrow_invocable_r_v
212     using Fn = CallObject<true, int>;
213     static_assert(std::is_nothrow_invocable_r_v<void, Fn>, "");
214     static_assert(!std::is_nothrow_invocable_r_v<int, Fn, int>, "");
215   }
216   test_noexcept_function_pointers();
217 
218   return 0;
219 }
220