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 { 24 Implicit(int) noexcept {} 25 }; 26 27 struct ThrowsImplicit { 28 ThrowsImplicit(int) {} 29 }; 30 31 struct Explicit { 32 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> 42 void operator()(Args&&...) const noexcept {} 43 }; 44 45 template <class Fn, class... Args> 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> 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 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 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