diff options
author | Eric Fiselier <eric@efcs.ca> | 2016-04-20 00:14:32 +0000 |
---|---|---|
committer | Eric Fiselier <eric@efcs.ca> | 2016-04-20 00:14:32 +0000 |
commit | 840fa745ca493123c44d7e9b62676f3a0cd23c0d (patch) | |
tree | 48f0ece836408898936fa627512b5422a3e562b2 /libcxx/test/std/utilities/meta/meta.rel | |
parent | 3eef9d180dbc9458f96f3e0f6a79fdee56bb8aae (diff) | |
download | bcm5719-llvm-840fa745ca493123c44d7e9b62676f3a0cd23c0d.tar.gz bcm5719-llvm-840fa745ca493123c44d7e9b62676f3a0cd23c0d.zip |
Add 'is_callable' and 'is_nothrow_callable' traits and cleanup INVOKE.
The primary purpose of this patch is to add the 'is_callable' traits.
Since 'is_nothrow_callable' required making 'INVOKE' conditionally noexcept
I also took this oppertunity to implement a constexpr version of INVOKE.
This fixes 'std::experimental::apply' which required constexpr 'INVOKE support'.
This patch will be followed up with some cleanup. Primarly removing most
of "__member_function_traits" since it's no longer used by INVOKE (in C++11 at least).
llvm-svn: 266836
Diffstat (limited to 'libcxx/test/std/utilities/meta/meta.rel')
-rw-r--r-- | libcxx/test/std/utilities/meta/meta.rel/is_callable.pass.cpp | 159 | ||||
-rw-r--r-- | libcxx/test/std/utilities/meta/meta.rel/is_nothrow_callable.pass.cpp | 115 |
2 files changed, 274 insertions, 0 deletions
diff --git a/libcxx/test/std/utilities/meta/meta.rel/is_callable.pass.cpp b/libcxx/test/std/utilities/meta/meta.rel/is_callable.pass.cpp new file mode 100644 index 00000000000..7de65835f73 --- /dev/null +++ b/libcxx/test/std/utilities/meta/meta.rel/is_callable.pass.cpp @@ -0,0 +1,159 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// type_traits + +// is_callable + +// Most testing of is_callable is done within the [meta.trans.other] result_of +// tests. + +#include <type_traits> +#include <functional> + +#include "test_macros.h" + +struct Tag {}; +struct DerFromTag : Tag {}; + +struct Implicit { + Implicit(int) {} +}; + +struct Explicit { + explicit Explicit(int) {} +}; + +struct NotCallableWithInt { + int operator()(int) = delete; + int operator()(Tag) { return 42; } +}; + +int main() +{ + { + using Fn = int(Tag::*)(int); + using RFn = int(Tag::*)(int) &&; + // INVOKE bullet 1, 2 and 3 + { + // Bullet 1 + static_assert(std::is_callable<Fn(Tag&, int)>::value); + static_assert(std::is_callable<Fn(DerFromTag&, int)>::value); + static_assert(std::is_callable<RFn(Tag&&, int)>::value); + static_assert(!std::is_callable<RFn(Tag&, int)>::value); + static_assert(!std::is_callable<Fn(Tag&)>::value); + static_assert(!std::is_callable<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_callable<Fn(T&, int)>::value); + static_assert(std::is_callable<Fn(DT&, int)>::value); + static_assert(std::is_callable<Fn(const T&, int)>::value); + static_assert(std::is_callable<Fn(T&&, int)>::value); + static_assert(!std::is_callable<Fn(CT&, int)>::value); + static_assert(!std::is_callable<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_callable<Fn(T&, int)>::value); + static_assert(std::is_callable<Fn(DT&, int)>::value); + static_assert(std::is_callable<Fn(const T&, int)>::value); + static_assert(std::is_callable<Fn(T&&, int)>::value); + static_assert(std::is_callable<Fn(ST, int)>::value); + static_assert(!std::is_callable<Fn(CT&, int)>::value); + static_assert(!std::is_callable<RFn(T, int)>::value); + } + } + { + // Bullets 4, 5 and 6 + using Fn = int (Tag::*); + static_assert(!std::is_callable<Fn()>::value); + { + // Bullet 4 + static_assert(std::is_callable<Fn(Tag&)>::value); + static_assert(std::is_callable<Fn(DerFromTag&)>::value); + static_assert(std::is_callable<Fn(Tag&&)>::value); + static_assert(std::is_callable<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_callable<Fn(T&)>::value); + static_assert(std::is_callable<Fn(DT&)>::value); + static_assert(std::is_callable<Fn(const T&)>::value); + static_assert(std::is_callable<Fn(T&&)>::value); + static_assert(std::is_callable<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_callable<Fn(T&)>::value); + static_assert(std::is_callable<Fn(DT&)>::value); + static_assert(std::is_callable<Fn(const T&)>::value); + static_assert(std::is_callable<Fn(T&&)>::value); + static_assert(std::is_callable<Fn(ST)>::value); + static_assert(std::is_callable<Fn(CT&)>::value); + } + } + { + // INVOKE bullet 7 + { + // Function pointer + using Fp = void(*)(Tag&, int); + static_assert(std::is_callable<Fp(Tag&, int)>::value); + static_assert(std::is_callable<Fp(DerFromTag&, int)>::value); + static_assert(!std::is_callable<Fp(const Tag&, int)>::value); + static_assert(!std::is_callable<Fp()>::value); + static_assert(!std::is_callable<Fp(Tag&)>::value); + } + { + // Function reference + using Fp = void(&)(Tag&, int); + static_assert(std::is_callable<Fp(Tag&, int)>::value); + static_assert(std::is_callable<Fp(DerFromTag&, int)>::value); + static_assert(!std::is_callable<Fp(const Tag&, int)>::value); + static_assert(!std::is_callable<Fp()>::value); + static_assert(!std::is_callable<Fp(Tag&)>::value); + } + { + // Function object + using Fn = NotCallableWithInt; + static_assert(std::is_callable<Fn(Tag)>::value, ""); + static_assert(!std::is_callable<Fn(int)>::value, ""); + } + } + { + // Check that the conversion to the return type is properly checked + using Fn = int(*)(); + static_assert(std::is_callable<Fn(), Implicit>::value); + static_assert(std::is_callable<Fn(), double>::value); + static_assert(std::is_callable<Fn(), const volatile void>::value); + static_assert(!std::is_callable<Fn(), Explicit>::value); + } + { + // Check for is_callable_v + using Fn = void(*)(); + static_assert(std::is_callable_v<Fn()>); + static_assert(!std::is_callable_v<Fn(int)>); + } +} diff --git a/libcxx/test/std/utilities/meta/meta.rel/is_nothrow_callable.pass.cpp b/libcxx/test/std/utilities/meta/meta.rel/is_nothrow_callable.pass.cpp new file mode 100644 index 00000000000..c36a460af34 --- /dev/null +++ b/libcxx/test/std/utilities/meta/meta.rel/is_nothrow_callable.pass.cpp @@ -0,0 +1,115 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// type_traits + +// is_nothrow_callable + +#include <type_traits> +#include <functional> + +#include "test_macros.h" + +struct Tag {}; + +struct Implicit { + Implicit(int) noexcept {} +}; + +struct ThrowsImplicit { + ThrowsImplicit(int) {} +}; + +struct Explicit { + explicit Explicit(int) noexcept {} +}; + +template <bool IsNoexcept, class Ret, class ...Args> +struct CallObject { + Ret operator()(Args&&...) const noexcept(IsNoexcept); +}; + +template <class Fn> +constexpr bool throws_callable() { + return std::is_callable<Fn>::value && + !std::is_nothrow_callable<Fn>::value; +} + +template <class Fn, class Ret> +constexpr bool throws_callable() { + return std::is_callable<Fn, Ret>::value && + !std::is_nothrow_callable<Fn, Ret>::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; }; +#if !defined(__cpp_noexcept_function_type) + { + // Check that PMF's and function pointers *work*. is_nothrow_callable will always + // return false because 'noexcept' is not part of the function type. + static_assert(throws_callable<decltype(&Dummy::foo)(Dummy&)>()); + static_assert(throws_callable<decltype(&Dummy::bar)()>()); + } +#else + { + // Check that PMF's and function pointers actually work and that + // is_nothrow_callable returns true for noexcept PMF's and function + // pointers. + static_assert(std::is_nothrow_callable<decltype(&Dummy::foo)(Dummy&)>::value); + static_assert(std::is_nothrow_callable<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_callable<Fn(), Implicit>::value); + static_assert(std::is_nothrow_callable<Fn(), double>::value); + static_assert(std::is_nothrow_callable<Fn(), const volatile void>::value); + static_assert(throws_callable<Fn(), ThrowsImplicit>()); + static_assert(!std::is_nothrow_callable<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_callable<Fn(Implicit&, ThrowsImplicit&)>::value); + static_assert(std::is_nothrow_callable<Fn(int, ThrowsImplicit&)>::value); + static_assert(throws_callable<Fn(int, int)>()); + static_assert(!std::is_nothrow_callable<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_callable<Fn()>::value); + static_assert(throws_callable<Fn2()>()); + } + { + // Check that PMD derefs are noexcept + using Fn = int (Tag::*); + static_assert(std::is_nothrow_callable<Fn(Tag&)>::value); + static_assert(std::is_nothrow_callable<Fn(Tag&), Implicit>::value); + static_assert(throws_callable<Fn(Tag&), ThrowsImplicit>()); + } + { + // Check for is_nothrow_callable_v + using Fn = CallObject<true, int>; + static_assert(std::is_nothrow_callable_v<Fn()>); + static_assert(!std::is_nothrow_callable_v<Fn(int)>); + } + test_noexcept_function_pointers(); +} |