diff options
author | Eric Fiselier <eric@efcs.ca> | 2019-01-29 18:01:14 +0000 |
---|---|---|
committer | Eric Fiselier <eric@efcs.ca> | 2019-01-29 18:01:14 +0000 |
commit | 011943a6e805a7666a7bff90ba27cd766bcc3a58 (patch) | |
tree | b75e81f32fb2253a3cc0ce9323c2a835dcecbb52 /libcxx/test/std/utilities | |
parent | d13777aa18cfe2904110038429095433b92783f3 (diff) | |
download | bcm5719-llvm-011943a6e805a7666a7bff90ba27cd766bcc3a58.tar.gz bcm5719-llvm-011943a6e805a7666a7bff90ba27cd766bcc3a58.zip |
Fix PR40495 - is_invokable_v<void> does not compile
The meta-programming that attempted to form the invoke call expression
was not in a SFINAE context. This made it a hard error to provide
non-referencable types like 'void' or 'void (...) const'.
This patch fixes the error by checking the validity of the call
expression within a SFINAE context.
llvm-svn: 352522
Diffstat (limited to 'libcxx/test/std/utilities')
-rw-r--r-- | libcxx/test/std/utilities/meta/meta.rel/is_invocable.pass.cpp | 305 | ||||
-rw-r--r-- | libcxx/test/std/utilities/meta/meta.rel/is_nothrow_invocable.pass.cpp | 233 |
2 files changed, 356 insertions, 182 deletions
diff --git a/libcxx/test/std/utilities/meta/meta.rel/is_invocable.pass.cpp b/libcxx/test/std/utilities/meta/meta.rel/is_invocable.pass.cpp index a2dc0907208..dab17974bb8 100644 --- a/libcxx/test/std/utilities/meta/meta.rel/is_invocable.pass.cpp +++ b/libcxx/test/std/utilities/meta/meta.rel/is_invocable.pass.cpp @@ -15,9 +15,13 @@ // Most testing of is_invocable is done within the [meta.trans.other] result_of // tests. +// Fn and all types in the template parameter pack ArgTypes shall be +// complete types, cv void, or arrays of unknown bound. + #include <type_traits> #include <functional> #include <memory> +#include <vector> #include "test_macros.h" @@ -37,129 +41,204 @@ struct NotCallableWithInt { int operator()(Tag) { return 42; } }; -int main() -{ +struct Sink { + template <class ...Args> + void operator()(Args&&...) const {} +}; + +int main() { + using AbominableFunc = void(...) const; + + // Non-callable things + { + static_assert(!std::is_invocable<void>::value, ""); + static_assert(!std::is_invocable<const void>::value, ""); + static_assert(!std::is_invocable<volatile void>::value, ""); + static_assert(!std::is_invocable<const volatile void>::value, ""); + static_assert(!std::is_invocable<std::nullptr_t>::value, ""); + static_assert(!std::is_invocable<int>::value, ""); + static_assert(!std::is_invocable<double>::value, ""); + + static_assert(!std::is_invocable<int[]>::value, ""); + static_assert(!std::is_invocable<int[3]>::value, ""); + + static_assert(!std::is_invocable<int*>::value, ""); + static_assert(!std::is_invocable<const int*>::value, ""); + static_assert(!std::is_invocable<int const*>::value, ""); + + static_assert(!std::is_invocable<int&>::value, ""); + static_assert(!std::is_invocable<const int&>::value, ""); + static_assert(!std::is_invocable<int&&>::value, ""); + + static_assert(!std::is_invocable<std::vector<int> >::value, ""); + static_assert(!std::is_invocable<std::vector<int*> >::value, ""); + static_assert(!std::is_invocable<std::vector<int**> >::value, ""); + + static_assert(!std::is_invocable<AbominableFunc>::value, ""); + + // with parameters + static_assert(!std::is_invocable<int, int>::value, ""); + static_assert(!std::is_invocable<int, double, float>::value, ""); + static_assert(!std::is_invocable<int, char, float, double>::value, ""); + static_assert(!std::is_invocable<Sink, AbominableFunc>::value, ""); + static_assert(!std::is_invocable<Sink, void>::value, ""); + static_assert(!std::is_invocable<Sink, const volatile void>::value, + ""); + + + static_assert(!std::is_invocable_r<int, void>::value, ""); + static_assert(!std::is_invocable_r<int, const void>::value, ""); + static_assert(!std::is_invocable_r<int, volatile void>::value, ""); + static_assert(!std::is_invocable_r<int, const volatile void>::value, ""); + static_assert(!std::is_invocable_r<int, std::nullptr_t>::value, ""); + static_assert(!std::is_invocable_r<int, int>::value, ""); + static_assert(!std::is_invocable_r<int, double>::value, ""); + + static_assert(!std::is_invocable_r<int, int[]>::value, ""); + static_assert(!std::is_invocable_r<int, int[3]>::value, ""); + + static_assert(!std::is_invocable_r<int, int*>::value, ""); + static_assert(!std::is_invocable_r<int, const int*>::value, ""); + static_assert(!std::is_invocable_r<int, int const*>::value, ""); + + static_assert(!std::is_invocable_r<int, int&>::value, ""); + static_assert(!std::is_invocable_r<int, const int&>::value, ""); + static_assert(!std::is_invocable_r<int, int&&>::value, ""); + + static_assert(!std::is_invocable_r<int, std::vector<int> >::value, ""); + static_assert(!std::is_invocable_r<int, std::vector<int*> >::value, ""); + static_assert(!std::is_invocable_r<int, std::vector<int**> >::value, ""); + static_assert(!std::is_invocable_r<void, AbominableFunc>::value, ""); + + // with parameters + static_assert(!std::is_invocable_r<int, int, int>::value, ""); + static_assert(!std::is_invocable_r<int, int, double, float>::value, ""); + static_assert(!std::is_invocable_r<int, int, char, float, double>::value, + ""); + static_assert(!std::is_invocable_r<void, Sink, AbominableFunc>::value, ""); + static_assert(!std::is_invocable_r<void, Sink, void>::value, ""); + static_assert(!std::is_invocable_r<void, Sink, const volatile void>::value, + ""); + } + { + using Fn = int (Tag::*)(int); + using RFn = int (Tag::*)(int)&&; + // INVOKE bullet 1, 2 and 3 { - using Fn = int(Tag::*)(int); - using RFn = int(Tag::*)(int) &&; - // INVOKE bullet 1, 2 and 3 - { - // Bullet 1 - static_assert(std::is_invocable<Fn, Tag&, int>::value, ""); - static_assert(std::is_invocable<Fn, DerFromTag&, int>::value, ""); - static_assert(std::is_invocable<RFn, Tag&&, int>::value, ""); - static_assert(!std::is_invocable<RFn, Tag&, int>::value, ""); - static_assert(!std::is_invocable<Fn, Tag&>::value, ""); - static_assert(!std::is_invocable<Fn, Tag const&, int>::value, ""); - } - { - // Bullet 2 - using T = std::reference_wrapper<Tag>; - using DT = std::reference_wrapper<DerFromTag>; - using CT = std::reference_wrapper<const Tag>; - static_assert(std::is_invocable<Fn, T&, int>::value, ""); - static_assert(std::is_invocable<Fn, DT&, int>::value, ""); - static_assert(std::is_invocable<Fn, const T&, int>::value, ""); - static_assert(std::is_invocable<Fn, T&&, int>::value, ""); - static_assert(!std::is_invocable<Fn, CT&, int>::value, ""); - static_assert(!std::is_invocable<RFn, T, int>::value, ""); - } - { - // Bullet 3 - using T = Tag*; - using DT = DerFromTag*; - using CT = const Tag*; - using ST = std::unique_ptr<Tag>; - static_assert(std::is_invocable<Fn, T&, int>::value, ""); - static_assert(std::is_invocable<Fn, DT&, int>::value, ""); - static_assert(std::is_invocable<Fn, const T&, int>::value, ""); - static_assert(std::is_invocable<Fn, T&&, int>::value, ""); - static_assert(std::is_invocable<Fn, ST, int>::value, ""); - static_assert(!std::is_invocable<Fn, CT&, int>::value, ""); - static_assert(!std::is_invocable<RFn, T, int>::value, ""); - } + // Bullet 1 + static_assert(std::is_invocable<Fn, Tag&, int>::value, ""); + static_assert(std::is_invocable<Fn, DerFromTag&, int>::value, ""); + static_assert(std::is_invocable<RFn, Tag&&, int>::value, ""); + static_assert(!std::is_invocable<RFn, Tag&, int>::value, ""); + static_assert(!std::is_invocable<Fn, Tag&>::value, ""); + static_assert(!std::is_invocable<Fn, Tag const&, int>::value, ""); } { - // Bullets 4, 5 and 6 - using Fn = int (Tag::*); - static_assert(!std::is_invocable<Fn>::value, ""); - { - // Bullet 4 - static_assert(std::is_invocable<Fn, Tag&>::value, ""); - static_assert(std::is_invocable<Fn, DerFromTag&>::value, ""); - static_assert(std::is_invocable<Fn, Tag&&>::value, ""); - static_assert(std::is_invocable<Fn, Tag const&>::value, ""); - } - { - // Bullet 5 - using T = std::reference_wrapper<Tag>; - using DT = std::reference_wrapper<DerFromTag>; - using CT = std::reference_wrapper<const Tag>; - static_assert(std::is_invocable<Fn, T&>::value, ""); - static_assert(std::is_invocable<Fn, DT&>::value, ""); - static_assert(std::is_invocable<Fn, const T&>::value, ""); - static_assert(std::is_invocable<Fn, T&&>::value, ""); - static_assert(std::is_invocable<Fn, CT&>::value, ""); - } - { - // Bullet 6 - using T = Tag*; - using DT = DerFromTag*; - using CT = const Tag*; - using ST = std::unique_ptr<Tag>; - static_assert(std::is_invocable<Fn, T&>::value, ""); - static_assert(std::is_invocable<Fn, DT&>::value, ""); - static_assert(std::is_invocable<Fn, const T&>::value, ""); - static_assert(std::is_invocable<Fn, T&&>::value, ""); - static_assert(std::is_invocable<Fn, ST>::value, ""); - static_assert(std::is_invocable<Fn, CT&>::value, ""); - } + // Bullet 2 + using T = std::reference_wrapper<Tag>; + using DT = std::reference_wrapper<DerFromTag>; + using CT = std::reference_wrapper<const Tag>; + static_assert(std::is_invocable<Fn, T&, int>::value, ""); + static_assert(std::is_invocable<Fn, DT&, int>::value, ""); + static_assert(std::is_invocable<Fn, const T&, int>::value, ""); + static_assert(std::is_invocable<Fn, T&&, int>::value, ""); + static_assert(!std::is_invocable<Fn, CT&, int>::value, ""); + static_assert(!std::is_invocable<RFn, T, int>::value, ""); } { - // INVOKE bullet 7 - { - // Function pointer - using Fp = void(*)(Tag&, int); - static_assert(std::is_invocable<Fp, Tag&, int>::value, ""); - static_assert(std::is_invocable<Fp, DerFromTag&, int>::value, ""); - static_assert(!std::is_invocable<Fp, const Tag&, int>::value, ""); - static_assert(!std::is_invocable<Fp>::value, ""); - static_assert(!std::is_invocable<Fp, Tag&>::value, ""); - } - { - // Function reference - using Fp = void(&)(Tag&, int); - static_assert(std::is_invocable<Fp, Tag&, int>::value, ""); - static_assert(std::is_invocable<Fp, DerFromTag&, int>::value, ""); - static_assert(!std::is_invocable<Fp, const Tag&, int>::value, ""); - static_assert(!std::is_invocable<Fp>::value, ""); - static_assert(!std::is_invocable<Fp, Tag&>::value, ""); - } - { - // Function object - using Fn = NotCallableWithInt; - static_assert(std::is_invocable<Fn, Tag>::value, ""); - static_assert(!std::is_invocable<Fn, int>::value, ""); - } + // Bullet 3 + using T = Tag*; + using DT = DerFromTag*; + using CT = const Tag*; + using ST = std::unique_ptr<Tag>; + static_assert(std::is_invocable<Fn, T&, int>::value, ""); + static_assert(std::is_invocable<Fn, DT&, int>::value, ""); + static_assert(std::is_invocable<Fn, const T&, int>::value, ""); + static_assert(std::is_invocable<Fn, T&&, int>::value, ""); + static_assert(std::is_invocable<Fn, ST, int>::value, ""); + static_assert(!std::is_invocable<Fn, CT&, int>::value, ""); + static_assert(!std::is_invocable<RFn, T, int>::value, ""); } + } + { + // Bullets 4, 5 and 6 + using Fn = int(Tag::*); + static_assert(!std::is_invocable<Fn>::value, ""); { - // Check that the conversion to the return type is properly checked - using Fn = int(*)(); - static_assert(std::is_invocable_r<Implicit, Fn>::value, ""); - static_assert(std::is_invocable_r<double, Fn>::value, ""); - static_assert(std::is_invocable_r<const volatile void, Fn>::value, ""); - static_assert(!std::is_invocable_r<Explicit, Fn>::value, ""); + // Bullet 4 + static_assert(std::is_invocable<Fn, Tag&>::value, ""); + static_assert(std::is_invocable<Fn, DerFromTag&>::value, ""); + static_assert(std::is_invocable<Fn, Tag&&>::value, ""); + static_assert(std::is_invocable<Fn, Tag const&>::value, ""); } { - // Check for is_invocable_v - using Fn = void(*)(); - static_assert(std::is_invocable_v<Fn>, ""); - static_assert(!std::is_invocable_v<Fn, int>, ""); + // Bullet 5 + using T = std::reference_wrapper<Tag>; + using DT = std::reference_wrapper<DerFromTag>; + using CT = std::reference_wrapper<const Tag>; + static_assert(std::is_invocable<Fn, T&>::value, ""); + static_assert(std::is_invocable<Fn, DT&>::value, ""); + static_assert(std::is_invocable<Fn, const T&>::value, ""); + static_assert(std::is_invocable<Fn, T&&>::value, ""); + static_assert(std::is_invocable<Fn, CT&>::value, ""); } { - // Check for is_invocable_r_v - using Fn = void(*)(); - static_assert(std::is_invocable_r_v<void, Fn>, ""); - static_assert(!std::is_invocable_r_v<int, Fn>, ""); + // Bullet 6 + using T = Tag*; + using DT = DerFromTag*; + using CT = const Tag*; + using ST = std::unique_ptr<Tag>; + static_assert(std::is_invocable<Fn, T&>::value, ""); + static_assert(std::is_invocable<Fn, DT&>::value, ""); + static_assert(std::is_invocable<Fn, const T&>::value, ""); + static_assert(std::is_invocable<Fn, T&&>::value, ""); + static_assert(std::is_invocable<Fn, ST>::value, ""); + static_assert(std::is_invocable<Fn, CT&>::value, ""); } + } + { // INVOKE bullet 7 + {// Function pointer + using Fp = void(*)(Tag&, int); + static_assert(std::is_invocable<Fp, Tag&, int>::value, ""); + static_assert(std::is_invocable<Fp, DerFromTag&, int>::value, ""); + static_assert(!std::is_invocable<Fp, const Tag&, int>::value, ""); + static_assert(!std::is_invocable<Fp>::value, ""); + static_assert(!std::is_invocable<Fp, Tag&>::value, ""); +} +{ + // Function reference + using Fp = void (&)(Tag&, int); + static_assert(std::is_invocable<Fp, Tag&, int>::value, ""); + static_assert(std::is_invocable<Fp, DerFromTag&, int>::value, ""); + static_assert(!std::is_invocable<Fp, const Tag&, int>::value, ""); + static_assert(!std::is_invocable<Fp>::value, ""); + static_assert(!std::is_invocable<Fp, Tag&>::value, ""); +} +{ + // Function object + using Fn = NotCallableWithInt; + static_assert(std::is_invocable<Fn, Tag>::value, ""); + static_assert(!std::is_invocable<Fn, int>::value, ""); +} +} +{ + // Check that the conversion to the return type is properly checked + using Fn = int (*)(); + static_assert(std::is_invocable_r<Implicit, Fn>::value, ""); + static_assert(std::is_invocable_r<double, Fn>::value, ""); + static_assert(std::is_invocable_r<const volatile void, Fn>::value, ""); + static_assert(!std::is_invocable_r<Explicit, Fn>::value, ""); +} +{ + // Check for is_invocable_v + using Fn = void (*)(); + static_assert(std::is_invocable_v<Fn>, ""); + static_assert(!std::is_invocable_v<Fn, int>, ""); +} +{ + // Check for is_invocable_r_v + using Fn = void (*)(); + static_assert(std::is_invocable_r_v<void, Fn>, ""); + static_assert(!std::is_invocable_r_v<int, Fn>, ""); +} } diff --git a/libcxx/test/std/utilities/meta/meta.rel/is_nothrow_invocable.pass.cpp b/libcxx/test/std/utilities/meta/meta.rel/is_nothrow_invocable.pass.cpp index e4ce36b505c..f21e99b02d0 100644 --- a/libcxx/test/std/utilities/meta/meta.rel/is_nothrow_invocable.pass.cpp +++ b/libcxx/test/std/utilities/meta/meta.rel/is_nothrow_invocable.pass.cpp @@ -14,6 +14,7 @@ #include <type_traits> #include <functional> +#include <vector> #include "test_macros.h" @@ -31,90 +32,184 @@ struct Explicit { explicit Explicit(int) noexcept {} }; -template <bool IsNoexcept, class Ret, class ...Args> +template <bool IsNoexcept, class Ret, class... Args> struct CallObject { Ret operator()(Args&&...) const noexcept(IsNoexcept); }; -template <class Fn, class ...Args> +struct Sink { + template <class... Args> + void operator()(Args&&...) const noexcept {} +}; + +template <class Fn, class... Args> constexpr bool throws_invocable() { - return std::is_invocable<Fn, Args...>::value && - !std::is_nothrow_invocable<Fn, Args...>::value; + return std::is_invocable<Fn, Args...>::value && + !std::is_nothrow_invocable<Fn, Args...>::value; } -template <class Ret, class Fn, class ...Args> +template <class Ret, class Fn, class... Args> constexpr bool throws_invocable_r() { - return std::is_invocable_r<Ret, Fn, Args...>::value && - !std::is_nothrow_invocable_r<Ret, Fn, Args...>::value; + return std::is_invocable_r<Ret, Fn, Args...>::value && + !std::is_nothrow_invocable_r<Ret, Fn, Args...>::value; } // FIXME(EricWF) Don't test the where noexcept is *not* part of the type system // once implementations have caught up. -void test_noexcept_function_pointers() -{ - struct Dummy { void foo() noexcept {} static void bar() noexcept {} }; +void test_noexcept_function_pointers() { + struct Dummy { + void foo() noexcept {} + static void bar() noexcept {} + }; #if !defined(__cpp_noexcept_function_type) - { - // Check that PMF's and function pointers *work*. is_nothrow_invocable will always - // return false because 'noexcept' is not part of the function type. - static_assert(throws_invocable<decltype(&Dummy::foo), Dummy&>(), ""); - static_assert(throws_invocable<decltype(&Dummy::bar)>(), ""); - } + { + // Check that PMF's and function pointers *work*. is_nothrow_invocable will always + // return false because 'noexcept' is not part of the function type. + static_assert(throws_invocable<decltype(&Dummy::foo), Dummy&>(), ""); + static_assert(throws_invocable<decltype(&Dummy::bar)>(), ""); + } #else - { - // Check that PMF's and function pointers actually work and that - // is_nothrow_invocable returns true for noexcept PMF's and function - // pointers. - static_assert(std::is_nothrow_invocable<decltype(&Dummy::foo), Dummy&>::value, ""); - static_assert(std::is_nothrow_invocable<decltype(&Dummy::bar)>::value, ""); - } + { + // Check that PMF's and function pointers actually work and that + // is_nothrow_invocable returns true for noexcept PMF's and function + // pointers. + static_assert( + std::is_nothrow_invocable<decltype(&Dummy::foo), Dummy&>::value, ""); + static_assert(std::is_nothrow_invocable<decltype(&Dummy::bar)>::value, ""); + } #endif } -int main() -{ - { - // Check that the conversion to the return type is properly checked - using Fn = CallObject<true, int>; - static_assert(std::is_nothrow_invocable_r<Implicit, Fn>::value, ""); - static_assert(std::is_nothrow_invocable_r<double, Fn>::value, ""); - static_assert(std::is_nothrow_invocable_r<const volatile void, Fn>::value, ""); - static_assert(throws_invocable_r<ThrowsImplicit, Fn>(), ""); - static_assert(!std::is_nothrow_invocable<Fn(), Explicit>(), ""); - } - { - // Check that the conversion to the parameters is properly checked - using Fn = CallObject<true, void, const Implicit&, const ThrowsImplicit&>; - static_assert(std::is_nothrow_invocable<Fn, Implicit&, ThrowsImplicit&>::value, ""); - static_assert(std::is_nothrow_invocable<Fn, int, ThrowsImplicit&>::value, ""); - static_assert(throws_invocable<Fn, int, int>(), ""); - static_assert(!std::is_nothrow_invocable<Fn>::value, ""); - } - { - // Check that the noexcept-ness of function objects is checked. - using Fn = CallObject<true, void>; - using Fn2 = CallObject<false, void>; - static_assert(std::is_nothrow_invocable<Fn>::value, ""); - static_assert(throws_invocable<Fn2>(), ""); - } - { - // Check that PMD derefs are noexcept - using Fn = int (Tag::*); - static_assert(std::is_nothrow_invocable<Fn, Tag&>::value, ""); - static_assert(std::is_nothrow_invocable_r<Implicit, Fn, Tag&>::value, ""); - static_assert(throws_invocable_r<ThrowsImplicit, Fn, Tag&>(), ""); - } - { - // Check for is_nothrow_invocable_v - using Fn = CallObject<true, int>; - static_assert(std::is_nothrow_invocable_v<Fn>, ""); - static_assert(!std::is_nothrow_invocable_v<Fn, int>, ""); - } - { - // Check for is_nothrow_invocable_r_v - using Fn = CallObject<true, int>; - static_assert(std::is_nothrow_invocable_r_v<void, Fn>, ""); - static_assert(!std::is_nothrow_invocable_r_v<int, Fn, int>, ""); - } - test_noexcept_function_pointers(); +int main() { + using AbominableFunc = void(...) const noexcept; + // Non-callable things + { + static_assert(!std::is_nothrow_invocable<void>::value, ""); + static_assert(!std::is_nothrow_invocable<const void>::value, ""); + static_assert(!std::is_nothrow_invocable<volatile void>::value, ""); + static_assert(!std::is_nothrow_invocable<const volatile void>::value, ""); + static_assert(!std::is_nothrow_invocable<std::nullptr_t>::value, ""); + static_assert(!std::is_nothrow_invocable<int>::value, ""); + static_assert(!std::is_nothrow_invocable<double>::value, ""); + + static_assert(!std::is_nothrow_invocable<int[]>::value, ""); + static_assert(!std::is_nothrow_invocable<int[3]>::value, ""); + + static_assert(!std::is_nothrow_invocable<int*>::value, ""); + static_assert(!std::is_nothrow_invocable<const int*>::value, ""); + static_assert(!std::is_nothrow_invocable<int const*>::value, ""); + + static_assert(!std::is_nothrow_invocable<int&>::value, ""); + static_assert(!std::is_nothrow_invocable<const int&>::value, ""); + static_assert(!std::is_nothrow_invocable<int&&>::value, ""); + + static_assert(!std::is_nothrow_invocable<int, std::vector<int> >::value, + ""); + static_assert(!std::is_nothrow_invocable<int, std::vector<int*> >::value, + ""); + static_assert(!std::is_nothrow_invocable<int, std::vector<int**> >::value, + ""); + + static_assert(!std::is_nothrow_invocable<AbominableFunc>::value, ""); + + // with parameters + static_assert(!std::is_nothrow_invocable<int, int>::value, ""); + static_assert(!std::is_nothrow_invocable<int, double, float>::value, ""); + static_assert(!std::is_nothrow_invocable<int, char, float, double>::value, + ""); + static_assert(!std::is_nothrow_invocable<Sink, AbominableFunc>::value, ""); + static_assert(!std::is_nothrow_invocable<Sink, void>::value, ""); + static_assert(!std::is_nothrow_invocable<Sink, const volatile void>::value, + ""); + + static_assert(!std::is_nothrow_invocable_r<int, void>::value, ""); + static_assert(!std::is_nothrow_invocable_r<int, const void>::value, ""); + static_assert(!std::is_nothrow_invocable_r<int, volatile void>::value, ""); + static_assert(!std::is_nothrow_invocable_r<int, const volatile void>::value, + ""); + static_assert(!std::is_nothrow_invocable_r<int, std::nullptr_t>::value, ""); + static_assert(!std::is_nothrow_invocable_r<int, int>::value, ""); + static_assert(!std::is_nothrow_invocable_r<int, double>::value, ""); + + static_assert(!std::is_nothrow_invocable_r<int, int[]>::value, ""); + static_assert(!std::is_nothrow_invocable_r<int, int[3]>::value, ""); + + static_assert(!std::is_nothrow_invocable_r<int, int*>::value, ""); + static_assert(!std::is_nothrow_invocable_r<int, const int*>::value, ""); + static_assert(!std::is_nothrow_invocable_r<int, int const*>::value, ""); + + static_assert(!std::is_nothrow_invocable_r<int, int&>::value, ""); + static_assert(!std::is_nothrow_invocable_r<int, const int&>::value, ""); + static_assert(!std::is_nothrow_invocable_r<int, int&&>::value, ""); + + static_assert(!std::is_nothrow_invocable_r<int, std::vector<int> >::value, + ""); + static_assert(!std::is_nothrow_invocable_r<int, std::vector<int*> >::value, + ""); + static_assert(!std::is_nothrow_invocable_r<int, std::vector<int**> >::value, + ""); + static_assert(!std::is_nothrow_invocable_r<void, AbominableFunc>::value, + ""); + + // with parameters + static_assert(!std::is_nothrow_invocable_r<int, int, int>::value, ""); + static_assert(!std::is_nothrow_invocable_r<int, int, double, float>::value, + ""); + static_assert( + !std::is_nothrow_invocable_r<int, int, char, float, double>::value, ""); + static_assert( + !std::is_nothrow_invocable_r<void, Sink, AbominableFunc>::value, ""); + static_assert(!std::is_nothrow_invocable_r<void, Sink, void>::value, ""); + static_assert( + !std::is_nothrow_invocable_r<void, Sink, const volatile void>::value, + ""); + } + + { + // Check that the conversion to the return type is properly checked + using Fn = CallObject<true, int>; + static_assert(std::is_nothrow_invocable_r<Implicit, Fn>::value, ""); + static_assert(std::is_nothrow_invocable_r<double, Fn>::value, ""); + static_assert(std::is_nothrow_invocable_r<const volatile void, Fn>::value, + ""); + static_assert(throws_invocable_r<ThrowsImplicit, Fn>(), ""); + static_assert(!std::is_nothrow_invocable<Fn(), Explicit>(), ""); + } + { + // Check that the conversion to the parameters is properly checked + using Fn = CallObject<true, void, const Implicit&, const ThrowsImplicit&>; + static_assert( + std::is_nothrow_invocable<Fn, Implicit&, ThrowsImplicit&>::value, ""); + static_assert(std::is_nothrow_invocable<Fn, int, ThrowsImplicit&>::value, + ""); + static_assert(throws_invocable<Fn, int, int>(), ""); + static_assert(!std::is_nothrow_invocable<Fn>::value, ""); + } + { + // Check that the noexcept-ness of function objects is checked. + using Fn = CallObject<true, void>; + using Fn2 = CallObject<false, void>; + static_assert(std::is_nothrow_invocable<Fn>::value, ""); + static_assert(throws_invocable<Fn2>(), ""); + } + { + // Check that PMD derefs are noexcept + using Fn = int(Tag::*); + static_assert(std::is_nothrow_invocable<Fn, Tag&>::value, ""); + static_assert(std::is_nothrow_invocable_r<Implicit, Fn, Tag&>::value, ""); + static_assert(throws_invocable_r<ThrowsImplicit, Fn, Tag&>(), ""); + } + { + // Check for is_nothrow_invocable_v + using Fn = CallObject<true, int>; + static_assert(std::is_nothrow_invocable_v<Fn>, ""); + static_assert(!std::is_nothrow_invocable_v<Fn, int>, ""); + } + { + // Check for is_nothrow_invocable_r_v + using Fn = CallObject<true, int>; + static_assert(std::is_nothrow_invocable_r_v<void, Fn>, ""); + static_assert(!std::is_nothrow_invocable_r_v<int, Fn, int>, ""); + } + test_noexcept_function_pointers(); } |