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