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