summaryrefslogtreecommitdiffstats
path: root/libcxx/test/std/utilities/meta/meta.rel
diff options
context:
space:
mode:
authorEric Fiselier <eric@efcs.ca>2016-04-20 00:14:32 +0000
committerEric Fiselier <eric@efcs.ca>2016-04-20 00:14:32 +0000
commit840fa745ca493123c44d7e9b62676f3a0cd23c0d (patch)
tree48f0ece836408898936fa627512b5422a3e562b2 /libcxx/test/std/utilities/meta/meta.rel
parent3eef9d180dbc9458f96f3e0f6a79fdee56bb8aae (diff)
downloadbcm5719-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.cpp159
-rw-r--r--libcxx/test/std/utilities/meta/meta.rel/is_nothrow_callable.pass.cpp115
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();
+}
OpenPOWER on IntegriCloud