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).
git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@266836 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/__functional_base b/include/__functional_base
index 3274842..feb587f 100644
--- a/include/__functional_base
+++ b/include/__functional_base
@@ -306,97 +306,19 @@
#endif // _LIBCPP_HAS_NO_VARIADICS
-// __invoke
+#ifndef _LIBCPP_CXX03_LANG
-#ifndef _LIBCPP_HAS_NO_VARIADICS
-
-// bullets 1 and 2
-
-template <class _Fp, class _A0, class ..._Args,
- class>
-inline _LIBCPP_INLINE_VISIBILITY
-auto
-__invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
- -> decltype((_VSTD::forward<_A0>(__a0).*__f)(_VSTD::forward<_Args>(__args)...))
-{
- return (_VSTD::forward<_A0>(__a0).*__f)(_VSTD::forward<_Args>(__args)...);
-}
-
-
-template <class _Fp, class _A0, class ..._Args,
- class>
-inline _LIBCPP_INLINE_VISIBILITY
-auto
-__invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
- -> decltype((__a0.get().*__f)(_VSTD::forward<_Args>(__args)...))
-{
- return (__a0.get().*__f)(_VSTD::forward<_Args>(__args)...);
-}
-
-template <class _Fp, class _A0, class ..._Args,
- class>
-inline _LIBCPP_INLINE_VISIBILITY
-auto
-__invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
- -> decltype(((*_VSTD::forward<_A0>(__a0)).*__f)(_VSTD::forward<_Args>(__args)...))
-{
- return ((*_VSTD::forward<_A0>(__a0)).*__f)(_VSTD::forward<_Args>(__args)...);
-}
-
-// bullets 3 and 4
-
-template <class _Fp, class _A0,
- class>
-inline _LIBCPP_INLINE_VISIBILITY
-auto
-__invoke(_Fp&& __f, _A0&& __a0)
- -> decltype(_VSTD::forward<_A0>(__a0).*__f)
-{
- return _VSTD::forward<_A0>(__a0).*__f;
-}
-
-
-template <class _Fp, class _A0,
- class>
-inline _LIBCPP_INLINE_VISIBILITY
-auto
-__invoke(_Fp&& __f, _A0&& __a0)
- -> decltype(__a0.get().*__f)
-{
- return __a0.get().*__f;
-}
-
-template <class _Fp, class _A0,
- class>
-inline _LIBCPP_INLINE_VISIBILITY
-auto
-__invoke(_Fp&& __f, _A0&& __a0)
- -> decltype((*_VSTD::forward<_A0>(__a0)).*__f)
-{
- return (*_VSTD::forward<_A0>(__a0)).*__f;
-}
-
-// bullet 5
-
-template <class _Fp, class ..._Args>
-inline _LIBCPP_INLINE_VISIBILITY
-auto
-__invoke(_Fp&& __f, _Args&& ...__args)
- -> decltype(_VSTD::forward<_Fp>(__f)(_VSTD::forward<_Args>(__args)...))
-{
- return _VSTD::forward<_Fp>(__f)(_VSTD::forward<_Args>(__args)...);
-}
template <class _Tp, class ..._Args>
struct __invoke_return
{
typedef decltype(__invoke(_VSTD::declval<_Tp>(), _VSTD::declval<_Args>()...)) type;
};
-#else // _LIBCPP_HAS_NO_VARIADICS
+#else // defined(_LIBCPP_CXX03_LANG)
#include <__functional_base_03>
-#endif // _LIBCPP_HAS_NO_VARIADICS
+#endif // !defined(_LIBCPP_CXX03_LANG)
template <class _Ret>
diff --git a/include/experimental/tuple b/include/experimental/tuple
index 50d1e05..e00d2ec 100644
--- a/include/experimental/tuple
+++ b/include/experimental/tuple
@@ -57,9 +57,10 @@
template <class _Fn, class _Tuple, size_t ..._Id>
inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_CONSTEXPR_AFTER_CXX11
decltype(auto) __apply_tuple_impl(_Fn && __f, _Tuple && __t,
integer_sequence<size_t, _Id...>) {
- return _VSTD::__invoke(
+ return _VSTD::__invoke_constexpr(
_VSTD::forward<_Fn>(__f),
_VSTD::get<_Id>(_VSTD::forward<_Tuple>(__t))...
);
diff --git a/include/type_traits b/include/type_traits
index d4b857e..b4af37d 100644
--- a/include/type_traits
+++ b/include/type_traits
@@ -132,6 +132,14 @@
template <class Base, class Derived> struct is_base_of;
template <class From, class To> struct is_convertible;
+ template <class, class R = void> struct is_callable; // not defined
+ template <class Fn, class... ArgTypes, class R>
+ struct is_callable<Fn(ArgTypes...), R>;
+
+ template <class, class R = void> struct is_nothrow_callable; // not defined
+ template <class Fn, class... ArgTypes, class R>
+ struct is_nothrow_callable<Fn(ArgTypes...), R>;
+
// Alignment properties and transformations:
template <class T> struct alignment_of;
template <size_t Len, size_t Align = most_stringent_alignment_requirement>
@@ -344,6 +352,10 @@
= is_base_of<Base, Derived>::value; // C++17
template <class From, class To> constexpr bool is_convertible_v
= is_convertible<From, To>::value; // C++17
+ template <class T, class R = void> constexpr bool is_callable_v
+ = is_callable<T, R>::value; // C++17
+ template <class T, class R = void> constexpr bool is_nothrow_callable_v
+ = is_nothrow_callable<T, R>::value; // C++17
// [meta.logical], logical operator traits:
template<class... B> struct conjunction; // C++17
@@ -2739,6 +2751,15 @@
// typedef ... _FnType;
};
+
+template <class _DecayedFp>
+struct __member_pointer_class_type {};
+
+template <class _Ret, class _ClassType>
+struct __member_pointer_class_type<_Ret _ClassType::*> {
+ typedef _ClassType type;
+};
+
// result_of
template <class _Callable> class result_of;
@@ -3971,7 +3992,7 @@
template <class _Tp> struct __is_reference_wrapper
: public __is_reference_wrapper_impl<typename remove_cv<_Tp>::type> {};
-#ifndef _LIBCPP_HAS_NO_VARIADICS
+#ifndef _LIBCPP_CXX03_LANG
// Check for complete types
@@ -4059,8 +4080,6 @@
{
};
-#if __has_feature(cxx_reference_qualified_functions)
-
template <class _Rp, class _Class, class ..._Param>
struct __check_complete<_Rp (_Class::*)(_Param...) &>
: private __check_complete<_Class>
@@ -4109,8 +4128,6 @@
{
};
-#endif
-
template <class _Rp, class _Class>
struct __check_complete<_Rp _Class::*>
: private __check_complete<_Class>
@@ -4118,149 +4135,250 @@
};
-template <class _Fp, class _A0>
-using __arg_is_base_of_ptm =
- is_base_of<typename remove_reference<typename __member_pointer_traits<typename remove_reference<_Fp>::type>::_ClassType>::type,
- typename remove_reference<_A0>::type>;
+template <class _Fp, class _A0,
+ class _DecayFp = typename decay<_Fp>::type,
+ class _DecayA0 = typename decay<_A0>::type,
+ class _ClassT = typename __member_pointer_class_type<_DecayFp>::type>
+using __enable_if_bullet1 = typename enable_if
+ <
+ is_member_function_pointer<_DecayFp>::value
+ && is_base_of<_ClassT, _DecayA0>::value
+ >::type;
-template <class _A0>
-using __arg_is_reference_wrapper = __is_reference_wrapper<typename decay<_A0>::type>;
+template <class _Fp, class _A0,
+ class _DecayFp = typename decay<_Fp>::type,
+ class _DecayA0 = typename decay<_A0>::type>
+using __enable_if_bullet2 = typename enable_if
+ <
+ is_member_function_pointer<_DecayFp>::value
+ && __is_reference_wrapper<_DecayA0>::value
+ >::type;
+
+template <class _Fp, class _A0,
+ class _DecayFp = typename decay<_Fp>::type,
+ class _DecayA0 = typename decay<_A0>::type,
+ class _ClassT = typename __member_pointer_class_type<_DecayFp>::type>
+using __enable_if_bullet3 = typename enable_if
+ <
+ is_member_function_pointer<_DecayFp>::value
+ && !is_base_of<_ClassT, _DecayA0>::value
+ && !__is_reference_wrapper<_DecayA0>::value
+ >::type;
+
+template <class _Fp, class _A0,
+ class _DecayFp = typename decay<_Fp>::type,
+ class _DecayA0 = typename decay<_A0>::type,
+ class _ClassT = typename __member_pointer_class_type<_DecayFp>::type>
+using __enable_if_bullet4 = typename enable_if
+ <
+ is_member_object_pointer<_DecayFp>::value
+ && is_base_of<_ClassT, _DecayA0>::value
+ >::type;
+
+template <class _Fp, class _A0,
+ class _DecayFp = typename decay<_Fp>::type,
+ class _DecayA0 = typename decay<_A0>::type>
+using __enable_if_bullet5 = typename enable_if
+ <
+ is_member_object_pointer<_DecayFp>::value
+ && __is_reference_wrapper<_DecayA0>::value
+ >::type;
+
+template <class _Fp, class _A0,
+ class _DecayFp = typename decay<_Fp>::type,
+ class _DecayA0 = typename decay<_A0>::type,
+ class _ClassT = typename __member_pointer_class_type<_DecayFp>::type>
+using __enable_if_bullet6 = typename enable_if
+ <
+ is_member_object_pointer<_DecayFp>::value
+ && !is_base_of<_ClassT, _DecayA0>::value
+ && !__is_reference_wrapper<_DecayA0>::value
+ >::type;
// __invoke forward declarations
// fall back - none of the bullets
+#define _LIBCPP_INVOKE_RETURN(...) \
+ noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) \
+ { return __VA_ARGS__; }
+
template <class ..._Args>
-auto
-__invoke(__any, _Args&& ...__args)
- -> __nat;
+auto __invoke(__any, _Args&& ...__args) -> __nat;
+
+template <class ..._Args>
+auto __invoke_constexpr(__any, _Args&& ...__args) -> __nat;
// bullets 1, 2 and 3
template <class _Fp, class _A0, class ..._Args,
- class = typename enable_if
- <
- is_member_function_pointer<typename remove_reference<_Fp>::type>::value &&
- __arg_is_base_of_ptm<_Fp, _A0>::value
- >::type
- >
-_LIBCPP_INLINE_VISIBILITY
+ class = __enable_if_bullet1<_Fp, _A0>>
+inline _LIBCPP_INLINE_VISIBILITY
auto
__invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
- -> decltype((_VSTD::forward<_A0>(__a0).*__f)(_VSTD::forward<_Args>(__args)...));
-
+_LIBCPP_INVOKE_RETURN((_VSTD::forward<_A0>(__a0).*__f)(_VSTD::forward<_Args>(__args)...))
template <class _Fp, class _A0, class ..._Args,
- class = typename enable_if
- <
- is_member_function_pointer<typename remove_reference<_Fp>::type>::value &&
- __arg_is_reference_wrapper<_A0>::value
- >::type
- >
-_LIBCPP_INLINE_VISIBILITY
-auto
-__invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
- -> decltype((__a0.get().*__f)(_VSTD::forward<_Args>(__args)...));
+ class = __enable_if_bullet1<_Fp, _A0>>
+inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_CONSTEXPR auto
+__invoke_constexpr(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
+_LIBCPP_INVOKE_RETURN((_VSTD::forward<_A0>(__a0).*__f)(_VSTD::forward<_Args>(__args)...))
template <class _Fp, class _A0, class ..._Args,
- class = typename enable_if
- <
- is_member_function_pointer<typename remove_reference<_Fp>::type>::value &&
- !__arg_is_base_of_ptm<_Fp, _A0>::value &&
- !__arg_is_reference_wrapper<_A0>::value
- >::type
- >
-_LIBCPP_INLINE_VISIBILITY
+ class = __enable_if_bullet2<_Fp, _A0>>
+inline _LIBCPP_INLINE_VISIBILITY
auto
__invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
- -> decltype(((*_VSTD::forward<_A0>(__a0)).*__f)(_VSTD::forward<_Args>(__args)...));
+_LIBCPP_INVOKE_RETURN((__a0.get().*__f)(_VSTD::forward<_Args>(__args)...))
+
+template <class _Fp, class _A0, class ..._Args,
+ class = __enable_if_bullet2<_Fp, _A0>>
+inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_CONSTEXPR auto
+__invoke_constexpr(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
+_LIBCPP_INVOKE_RETURN((__a0.get().*__f)(_VSTD::forward<_Args>(__args)...))
+
+template <class _Fp, class _A0, class ..._Args,
+ class = __enable_if_bullet3<_Fp, _A0>>
+inline _LIBCPP_INLINE_VISIBILITY
+auto
+__invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
+_LIBCPP_INVOKE_RETURN(((*_VSTD::forward<_A0>(__a0)).*__f)(_VSTD::forward<_Args>(__args)...))
+
+template <class _Fp, class _A0, class ..._Args,
+ class = __enable_if_bullet3<_Fp, _A0>>
+inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_CONSTEXPR auto
+__invoke_constexpr(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
+_LIBCPP_INVOKE_RETURN(((*_VSTD::forward<_A0>(__a0)).*__f)(_VSTD::forward<_Args>(__args)...))
// bullets 4, 5 and 6
template <class _Fp, class _A0,
- class = typename enable_if
- <
- is_member_object_pointer<typename remove_reference<_Fp>::type>::value &&
- __arg_is_base_of_ptm<_Fp, _A0>::value
- >::type
- >
-_LIBCPP_INLINE_VISIBILITY
+ class = __enable_if_bullet4<_Fp, _A0>>
+inline _LIBCPP_INLINE_VISIBILITY
auto
__invoke(_Fp&& __f, _A0&& __a0)
- -> decltype(_VSTD::forward<_A0>(__a0).*__f);
-
+_LIBCPP_INVOKE_RETURN(_VSTD::forward<_A0>(__a0).*__f)
template <class _Fp, class _A0,
- class = typename enable_if
- <
- is_member_object_pointer<typename remove_reference<_Fp>::type>::value &&
- __arg_is_reference_wrapper<_A0>::value
- >::type
- >
-_LIBCPP_INLINE_VISIBILITY
-auto
-__invoke(_Fp&& __f, _A0&& __a0)
- -> decltype(__a0.get().*__f);
+ class = __enable_if_bullet4<_Fp, _A0>>
+inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_CONSTEXPR auto
+__invoke_constexpr(_Fp&& __f, _A0&& __a0)
+_LIBCPP_INVOKE_RETURN(_VSTD::forward<_A0>(__a0).*__f)
template <class _Fp, class _A0,
- class = typename enable_if
- <
- is_member_object_pointer<typename remove_reference<_Fp>::type>::value &&
- !__arg_is_base_of_ptm<_Fp, _A0>::value &&
- !__arg_is_reference_wrapper<_A0>::value
- >::type
- >
-_LIBCPP_INLINE_VISIBILITY
+ class = __enable_if_bullet5<_Fp, _A0>>
+inline _LIBCPP_INLINE_VISIBILITY
auto
__invoke(_Fp&& __f, _A0&& __a0)
- -> decltype((*_VSTD::forward<_A0>(__a0)).*__f);
+_LIBCPP_INVOKE_RETURN(__a0.get().*__f)
+
+template <class _Fp, class _A0,
+ class = __enable_if_bullet5<_Fp, _A0>>
+inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_CONSTEXPR auto
+__invoke_constexpr(_Fp&& __f, _A0&& __a0)
+_LIBCPP_INVOKE_RETURN(__a0.get().*__f)
+
+template <class _Fp, class _A0,
+ class = __enable_if_bullet6<_Fp, _A0>>
+inline _LIBCPP_INLINE_VISIBILITY
+auto
+__invoke(_Fp&& __f, _A0&& __a0)
+_LIBCPP_INVOKE_RETURN((*_VSTD::forward<_A0>(__a0)).*__f)
+
+template <class _Fp, class _A0,
+ class = __enable_if_bullet6<_Fp, _A0>>
+inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_CONSTEXPR auto
+__invoke_constexpr(_Fp&& __f, _A0&& __a0)
+_LIBCPP_INVOKE_RETURN((*_VSTD::forward<_A0>(__a0)).*__f)
// bullet 7
template <class _Fp, class ..._Args>
-_LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY
auto
__invoke(_Fp&& __f, _Args&& ...__args)
- -> decltype(_VSTD::forward<_Fp>(__f)(_VSTD::forward<_Args>(__args)...));
+_LIBCPP_INVOKE_RETURN(_VSTD::forward<_Fp>(__f)(_VSTD::forward<_Args>(__args)...))
+
+template <class _Fp, class ..._Args>
+inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_CONSTEXPR auto
+__invoke_constexpr(_Fp&& __f, _Args&& ...__args)
+_LIBCPP_INVOKE_RETURN(_VSTD::forward<_Fp>(__f)(_VSTD::forward<_Args>(__args)...))
+
+#undef _LIBCPP_INVOKE_RETURN
// __invokable
-template <class _Fp, class ..._Args>
-struct __invokable_imp
+template <class _Ret, class _Fp, class ..._Args>
+struct __invokable_r
: private __check_complete<_Fp>
{
- typedef decltype(
- __invoke(_VSTD::declval<_Fp>(), _VSTD::declval<_Args>()...)
- ) type;
- static const bool value = !is_same<type, __nat>::value;
+ using _Result = decltype(
+ _VSTD::__invoke(_VSTD::declval<_Fp>(), _VSTD::declval<_Args>()...));
+
+ static const bool value =
+ conditional<
+ !is_same<_Result, __nat>::value,
+ typename conditional<
+ is_void<_Ret>::value,
+ true_type,
+ is_convertible<_Result, _Ret>
+ >::type,
+ false_type
+ >::type::value;
};
template <class _Fp, class ..._Args>
-struct __invokable
- : public integral_constant<bool,
- __invokable_imp<_Fp, _Args...>::value>
-{
+using __invokable = __invokable_r<void, _Fp, _Args...>;
+
+template <bool _IsInvokable, bool _IsCVVoid, class _Ret, class _Fp, class ..._Args>
+struct __nothrow_invokable_r_imp {
+ static const bool value = false;
};
-// __invoke_of
-
-template <bool _Invokable, class _Fp, class ..._Args>
-struct __invoke_of_imp // false
+template <class _Ret, class _Fp, class ..._Args>
+struct __nothrow_invokable_r_imp<true, false, _Ret, _Fp, _Args...>
{
+ typedef __nothrow_invokable_r_imp _ThisT;
+
+ template <class _Tp>
+ static void __test_noexcept(_Tp) noexcept;
+
+ static const bool value = noexcept(_ThisT::__test_noexcept<_Ret>(
+ _VSTD::__invoke(_VSTD::declval<_Fp>(), _VSTD::declval<_Args>()...)));
};
-template <class _Fp, class ..._Args>
-struct __invoke_of_imp<true, _Fp, _Args...>
+template <class _Ret, class _Fp, class ..._Args>
+struct __nothrow_invokable_r_imp<true, true, _Ret, _Fp, _Args...>
{
- typedef typename __invokable_imp<_Fp, _Args...>::type type;
+ static const bool value = noexcept(
+ _VSTD::__invoke(_VSTD::declval<_Fp>(), _VSTD::declval<_Args>()...));
};
+template <class _Ret, class _Fp, class ..._Args>
+using __nothrow_invokable_r =
+ __nothrow_invokable_r_imp<
+ __invokable_r<_Ret, _Fp, _Args...>::value,
+ is_void<_Ret>::value,
+ _Ret, _Fp, _Args...
+ >;
+
template <class _Fp, class ..._Args>
struct __invoke_of
- : public __invoke_of_imp<__invokable<_Fp, _Args...>::value, _Fp, _Args...>
+ : public enable_if<
+ __invokable<_Fp, _Args...>::value,
+ typename __invokable_r<void, _Fp, _Args...>::_Result>
{
};
+// result_of
+
template <class _Fp, class ..._Args>
class _LIBCPP_TYPE_VIS_ONLY result_of<_Fp(_Args...)>
: public __invoke_of<_Fp, _Args...>
@@ -4271,7 +4389,36 @@
template <class _Tp> using result_of_t = typename result_of<_Tp>::type;
#endif
-#endif // _LIBCPP_HAS_NO_VARIADICS
+#if _LIBCPP_STD_VER > 14
+
+// is_callable
+
+template <class _Fn, class _Ret = void>
+struct _LIBCPP_TYPE_VIS_ONLY is_callable;
+
+template <class _Fn, class ..._Args, class _Ret>
+struct _LIBCPP_TYPE_VIS_ONLY is_callable<_Fn(_Args...), _Ret>
+ : integral_constant<bool, __invokable_r<_Ret, _Fn, _Args...>::value> {};
+
+template <class _Fn, class _Ret = void>
+constexpr bool is_callable_v = is_callable<_Fn, _Ret>::value;
+
+// is_nothrow_callable
+
+template <class _Fn, class _Ret = void>
+struct _LIBCPP_TYPE_VIS_ONLY is_nothrow_callable;
+
+template <class _Fn, class ..._Args, class _Ret>
+struct _LIBCPP_TYPE_VIS_ONLY is_nothrow_callable<_Fn(_Args...), _Ret>
+ : integral_constant<bool, __nothrow_invokable_r<_Ret, _Fn, _Args...>::value>
+{};
+
+template <class _Fn, class _Ret = void>
+constexpr bool is_nothrow_callable_v = is_nothrow_callable<_Fn, _Ret>::value;
+
+#endif // _LIBCPP_STD_VER > 14
+
+#endif // !defined(_LIBCPP_CXX03_LANG)
template <class _Tp>
inline _LIBCPP_INLINE_VISIBILITY
diff --git a/test/std/experimental/utilities/tuple/tuple.apply/constexpr_types.pass.cpp b/test/std/experimental/utilities/tuple/tuple.apply/constexpr_types.pass.cpp
index 2d70048..5b8a8f0 100644
--- a/test/std/experimental/utilities/tuple/tuple.apply/constexpr_types.pass.cpp
+++ b/test/std/experimental/utilities/tuple/tuple.apply/constexpr_types.pass.cpp
@@ -9,11 +9,6 @@
// UNSUPPORTED: c++98, c++03, c++11
-// TODO(ericwf)
-// constexpr support temporarily reverted due to bug:
-// https://llvm.org/bugs/show_bug.cgi?id=23141
-// XFAIL: *
-
// <experimental/tuple>
// template <class F, class T> constexpr decltype(auto) apply(F &&, T &&)
diff --git a/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/PR23141_invoke_not_constexpr.pass.cpp b/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/PR23141_invoke_not_constexpr.pass.cpp
new file mode 100644
index 0000000..163b2d9
--- /dev/null
+++ b/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/PR23141_invoke_not_constexpr.pass.cpp
@@ -0,0 +1,35 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <functional>
+
+// template<CopyConstructible Fn, CopyConstructible... Types>
+// unspecified bind(Fn, Types...);
+// template<Returnable R, CopyConstructible Fn, CopyConstructible... Types>
+// unspecified bind(Fn, Types...);
+
+// https://llvm.org/bugs/show_bug.cgi?id=23141
+#include <functional>
+#include <type_traits>
+
+struct Fun
+{
+ template<typename T, typename U>
+ void operator()(T && t, U && u) const
+ {
+ static_assert(std::is_same<U, int &>::value, "");
+ }
+};
+
+int main()
+{
+ std::bind(Fun{}, std::placeholders::_1, 42)("hello");
+}
diff --git a/test/std/utilities/function.objects/func.require/bullet_1_2_3.pass.cpp b/test/std/utilities/function.objects/func.require/bullet_1_2_3.pass.cpp
index 09e8e21..509c751 100644
--- a/test/std/utilities/function.objects/func.require/bullet_1_2_3.pass.cpp
+++ b/test/std/utilities/function.objects/func.require/bullet_1_2_3.pass.cpp
@@ -260,8 +260,11 @@
DerivedFromRefWrap<int> d(x);
auto get_fn = &std::reference_wrapper<int>::get;
auto& ret = std::__invoke(get_fn, r);
+ auto& cret = std::__invoke_constexpr(get_fn, r);
assert(&ret == &x);
+ assert(&cret == &x);
auto& ret2 = std::__invoke(get_fn, d);
+ auto& cret2 = std::__invoke_constexpr(get_fn, d);
assert(&ret2 == &x);
auto& ret3 = std::__invoke(get_fn, r2);
assert(&ret3 == &x);
diff --git a/test/std/utilities/function.objects/func.require/bullet_4_5_6.pass.cpp b/test/std/utilities/function.objects/func.require/bullet_4_5_6.pass.cpp
index 2007c41..803c501 100644
--- a/test/std/utilities/function.objects/func.require/bullet_4_5_6.pass.cpp
+++ b/test/std/utilities/function.objects/func.require/bullet_4_5_6.pass.cpp
@@ -185,11 +185,22 @@
#else
void runTest(Fn M, T& obj, ObjectType* expect ) {
#endif
- static_assert((std::is_same<
- decltype(std::__invoke(M, std::forward<T>(obj))), Expect
- >::value), "");
- Expect e = std::__invoke(M, std::forward<T>(obj));
- assert(&e == expect);
+ {
+ static_assert((std::is_same<
+ decltype(std::__invoke(M, std::forward<T>(obj))), Expect
+ >::value), "");
+ Expect e = std::__invoke(M, std::forward<T>(obj));
+ assert(&e == expect);
+ }
+#if TEST_STD_VER >= 11
+ {
+ static_assert((std::is_same<
+ decltype(std::__invoke_constexpr(M, std::forward<T>(obj))), Expect
+ >::value), "");
+ Expect e = std::__invoke_constexpr(M, std::forward<T>(obj));
+ assert(&e == expect);
+ }
+#endif
}
};
diff --git a/test/std/utilities/function.objects/func.require/invoke_helpers.h b/test/std/utilities/function.objects/func.require/invoke_helpers.h
index 495703d..7e7a5fd 100644
--- a/test/std/utilities/function.objects/func.require/invoke_helpers.h
+++ b/test/std/utilities/function.objects/func.require/invoke_helpers.h
@@ -271,89 +271,185 @@
ArgType a0, a1, a2;
//==========================================================================
- // BULLET 1 AND 2 TEST METHODS
+ // BULLET 1, 2 AND 3 TEST METHODS
//==========================================================================
template <class MethodPtr, class ObjectT>
void runTestImp(Int<0>, MethodPtr ptr, ObjectT& object) {
- static_assert((std::is_same<
- decltype(std::__invoke(ptr, object_cast(object)))
- , CallRet>::value), "");
- assert(ID::unchecked_call == false);
- CallRet ret = std::__invoke(ptr, object_cast(object));
- assert(ID::checkCalled(ret));
+ {
+ static_assert((std::is_same<
+ decltype(std::__invoke(ptr, object_cast(object)))
+ , CallRet>::value), "");
+ assert(ID::unchecked_call == false);
+ CallRet ret = std::__invoke(ptr, object_cast(object));
+ assert(ID::checkCalled(ret));
+ }
+#if TEST_STD_VER >= 11
+ {
+ static_assert((std::is_same<
+ decltype(std::__invoke_constexpr(ptr, object_cast(object)))
+ , CallRet>::value), "");
+ assert(ID::unchecked_call == false);
+ CallRet ret = std::__invoke_constexpr(ptr, object_cast(object));
+ assert(ID::checkCalled(ret));
+ }
+#endif
}
template <class MethodPtr, class ObjectT>
void runTestImp(Int<1>, MethodPtr ptr, ObjectT& object) {
- static_assert((std::is_same<
- decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0)))
- , CallRet>::value), "");
- assert(ID::unchecked_call == false);
- CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0));
- assert(ID::checkCalled(ret));
+ {
+ static_assert((std::is_same<
+ decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0)))
+ , CallRet>::value), "");
+ assert(ID::unchecked_call == false);
+ CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0));
+ assert(ID::checkCalled(ret));
+ }
+#if TEST_STD_VER >= 11
+ {
+ static_assert((std::is_same<
+ decltype(std::__invoke_constexpr(ptr, object_cast(object), arg_cast(a0)))
+ , CallRet>::value), "");
+ assert(ID::unchecked_call == false);
+ CallRet ret = std::__invoke_constexpr(ptr, object_cast(object), arg_cast(a0));
+ assert(ID::checkCalled(ret));
+ }
+#endif
}
template <class MethodPtr, class ObjectT>
void runTestImp(Int<2>, MethodPtr ptr, ObjectT& object) {
- static_assert((std::is_same<
- decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1)))
- , CallRet>::value), "");
- assert(ID::unchecked_call == false);
- CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1));
- assert(ID::checkCalled(ret));
+ {
+ static_assert((std::is_same<
+ decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1)))
+ , CallRet>::value), "");
+ assert(ID::unchecked_call == false);
+ CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1));
+ assert(ID::checkCalled(ret));
+ }
+#if TEST_STD_VER >= 11
+ {
+ static_assert((std::is_same<
+ decltype(std::__invoke_constexpr(ptr, object_cast(object), arg_cast(a0), arg_cast(a1)))
+ , CallRet>::value), "");
+ assert(ID::unchecked_call == false);
+ CallRet ret = std::__invoke_constexpr(ptr, object_cast(object), arg_cast(a0), arg_cast(a1));
+ assert(ID::checkCalled(ret));
+ }
+#endif
}
template <class MethodPtr, class ObjectT>
void runTestImp(Int<3>, MethodPtr ptr, ObjectT& object) {
- static_assert((std::is_same<
- decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
- , CallRet>::value), "");
- assert(ID::unchecked_call == false);
- CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
- assert(ID::checkCalled(ret));
+ {
+ static_assert((std::is_same<
+ decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
+ , CallRet>::value), "");
+ assert(ID::unchecked_call == false);
+ CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
+ assert(ID::checkCalled(ret));
+ }
+#if TEST_STD_VER >= 11
+ {
+ static_assert((std::is_same<
+ decltype(std::__invoke_constexpr(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
+ , CallRet>::value), "");
+ assert(ID::unchecked_call == false);
+ CallRet ret = std::__invoke_constexpr(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
+ assert(ID::checkCalled(ret));
+ }
+#endif
}
//==========================================================================
- // BULLET 5 TEST METHODS
+ // BULLET 7 TEST METHODS
//==========================================================================
template <class ObjectT>
void runTestImp(Int<0>, ObjectT& object) {
- static_assert((std::is_same<
- decltype(std::__invoke(object_cast(object)))
- , CallRet>::value), "");
- assert(ID::unchecked_call == false);
- CallRet ret = std::__invoke(object_cast(object));
- assert(ID::checkCalled(ret));
+ {
+ static_assert((std::is_same<
+ decltype(std::__invoke(object_cast(object)))
+ , CallRet>::value), "");
+ assert(ID::unchecked_call == false);
+ CallRet ret = std::__invoke(object_cast(object));
+ assert(ID::checkCalled(ret));
+ }
+#if TEST_STD_VER >= 11
+ {
+ static_assert((std::is_same<
+ decltype(std::__invoke_constexpr(object_cast(object)))
+ , CallRet>::value), "");
+ assert(ID::unchecked_call == false);
+ CallRet ret = std::__invoke_constexpr(object_cast(object));
+ assert(ID::checkCalled(ret));
+ }
+#endif
}
template <class ObjectT>
void runTestImp(Int<1>, ObjectT& object) {
- static_assert((std::is_same<
- decltype(std::__invoke(object_cast(object), arg_cast(a0)))
- , CallRet>::value), "");
- assert(ID::unchecked_call == false);
- CallRet ret = std::__invoke(object_cast(object), arg_cast(a0));
- assert(ID::checkCalled(ret));
+ {
+ static_assert((std::is_same<
+ decltype(std::__invoke(object_cast(object), arg_cast(a0)))
+ , CallRet>::value), "");
+ assert(ID::unchecked_call == false);
+ CallRet ret = std::__invoke(object_cast(object), arg_cast(a0));
+ assert(ID::checkCalled(ret));
+ }
+#if TEST_STD_VER >= 11
+ {
+ static_assert((std::is_same<
+ decltype(std::__invoke_constexpr(object_cast(object), arg_cast(a0)))
+ , CallRet>::value), "");
+ assert(ID::unchecked_call == false);
+ CallRet ret = std::__invoke_constexpr(object_cast(object), arg_cast(a0));
+ assert(ID::checkCalled(ret));
+ }
+#endif
}
template <class ObjectT>
void runTestImp(Int<2>, ObjectT& object) {
- static_assert((std::is_same<
- decltype(std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1)))
- , CallRet>::value), "");
- assert(ID::unchecked_call == false);
- CallRet ret = std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1));
- assert(ID::checkCalled(ret));
+ {
+ static_assert((std::is_same<
+ decltype(std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1)))
+ , CallRet>::value), "");
+ assert(ID::unchecked_call == false);
+ CallRet ret = std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1));
+ assert(ID::checkCalled(ret));
+ }
+#if TEST_STD_VER >= 11
+ {
+ static_assert((std::is_same<
+ decltype(std::__invoke_constexpr(object_cast(object), arg_cast(a0), arg_cast(a1)))
+ , CallRet>::value), "");
+ assert(ID::unchecked_call == false);
+ CallRet ret = std::__invoke_constexpr(object_cast(object), arg_cast(a0), arg_cast(a1));
+ assert(ID::checkCalled(ret));
+ }
+#endif
}
template <class ObjectT>
void runTestImp(Int<3>, ObjectT& object) {
- static_assert((std::is_same<
- decltype(std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
- , CallRet>::value), "");
- assert(ID::unchecked_call == false);
- CallRet ret = std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
- assert(ID::checkCalled(ret));
+ {
+ static_assert((std::is_same<
+ decltype(std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
+ , CallRet>::value), "");
+ assert(ID::unchecked_call == false);
+ CallRet ret = std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
+ assert(ID::checkCalled(ret));
+ }
+#if TEST_STD_VER >= 11
+ {
+ static_assert((std::is_same<
+ decltype(std::__invoke_constexpr(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)))
+ , CallRet>::value), "");
+ assert(ID::unchecked_call == false);
+ CallRet ret = std::__invoke_constexpr(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2));
+ assert(ID::checkCalled(ret));
+ }
+#endif
}
};
diff --git a/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp b/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp
index aa77dab..3e4a99e 100644
--- a/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp
+++ b/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp
@@ -7,6 +7,8 @@
//
//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++98, c++03
+
// <memory>
// shared_ptr
@@ -55,7 +57,6 @@
}
assert(A::count == 0);
assert(test_allocator<A>::alloc_count == 0);
-#if __cplusplus >= 201103L
{
int i = 67;
char c = 'e';
@@ -74,5 +75,4 @@
assert(p->get_char() == 'f');
}
assert(A::count == 0);
-#endif
}
diff --git a/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_no_variadics.pass.cpp b/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_cxx03.pass.cpp
similarity index 98%
rename from test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_no_variadics.pass.cpp
rename to test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_cxx03.pass.cpp
index 8dcd50e..f6350c7 100644
--- a/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_no_variadics.pass.cpp
+++ b/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_cxx03.pass.cpp
@@ -14,7 +14,7 @@
// template<class T, class A, class... Args>
// shared_ptr<T> allocate_shared(const A& a, Args&&... args);
-#define _LIBCPP_HAS_NO_VARIADICS
+
#include <memory>
#include <new>
#include <cstdlib>
diff --git a/test/std/utilities/meta/meta.rel/is_callable.pass.cpp b/test/std/utilities/meta/meta.rel/is_callable.pass.cpp
new file mode 100644
index 0000000..7de6583
--- /dev/null
+++ b/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/test/std/utilities/meta/meta.rel/is_nothrow_callable.pass.cpp b/test/std/utilities/meta/meta.rel/is_nothrow_callable.pass.cpp
new file mode 100644
index 0000000..c36a460
--- /dev/null
+++ b/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();
+}
diff --git a/test/std/utilities/meta/meta.trans/meta.trans.other/result_of.pass.cpp b/test/std/utilities/meta/meta.trans/meta.trans.other/result_of.pass.cpp
index 3ac7d1b..fc01b22 100644
--- a/test/std/utilities/meta/meta.trans/meta.trans.other/result_of.pass.cpp
+++ b/test/std/utilities/meta/meta.trans/meta.trans.other/result_of.pass.cpp
@@ -45,6 +45,10 @@
template <class T, class U>
void test_result_of()
{
+#if TEST_STD_VER > 14
+ static_assert(std::is_callable<T>::value, "");
+ static_assert(std::is_callable<T, U>::value, "");
+#endif
static_assert((std::is_same<typename std::result_of<T>::type, U>::value), "");
}
@@ -54,6 +58,9 @@
#if TEST_STD_VER >= 11
static_assert((!HasType<std::result_of<T> >::value), "");
#endif
+#if TEST_STD_VER > 14
+ static_assert(std::is_callable<T>::value == false, "");
+#endif
}
int main()
diff --git a/test/std/utilities/meta/meta.trans/meta.trans.other/result_of11.pass.cpp b/test/std/utilities/meta/meta.trans/meta.trans.other/result_of11.pass.cpp
index a008873..8cb5853 100644
--- a/test/std/utilities/meta/meta.trans/meta.trans.other/result_of11.pass.cpp
+++ b/test/std/utilities/meta/meta.trans/meta.trans.other/result_of11.pass.cpp
@@ -35,6 +35,10 @@
#if TEST_STD_VER > 11
static_assert((std::is_same<std::result_of_t<T>, U>::value), "");
#endif
+#if TEST_STD_VER > 14
+ static_assert(std::is_callable<T>::value, "");
+ static_assert(std::is_callable<T, U>::value, "");
+#endif
}
int main()
diff --git a/www/cxx1z_status.html b/www/cxx1z_status.html
index 1c8e0db..41a6978 100644
--- a/www/cxx1z_status.html
+++ b/www/cxx1z_status.html
@@ -92,7 +92,7 @@
<tr><td><a href="http://wg21.link/P0030R1">P0030R1</a></td><td>LWG</td><td>Proposal to Introduce a 3-Argument Overload to std::hypot</td><td>Jacksonville</td><td></td><td></td></tr>
<tr><td><a href="http://wg21.link/P0031R0">P0031R0</a></td><td>LWG</td><td>A Proposal to Add Constexpr Modifiers to reverse_iterator, move_iterator, array and Range Access</td><td>Jacksonville</td><td></td><td></td></tr>
<tr><td><a href="http://wg21.link/P0272R1">P0272R1</a></td><td>LWG</td><td>Give <tt>std::string</tt> a non-const <tt>.data()</tt> member function</td><td>Jacksonville</td><td>Complete</td><td>3.9</td></tr>
- <tr><td><a href="http://wg21.link/P0077R2">P0077R2</a></td><td>LWG</td><td><tt>is_callable</tt>, the missing INVOKE related trait</td><td>Jacksonville</td><td></td><td></td></tr>
+ <tr><td><a href="http://wg21.link/P0077R2">P0077R2</a></td><td>LWG</td><td><tt>is_callable</tt>, the missing INVOKE related trait</td><td>Jacksonville</td><td>Complete</td><td>3.9</td></tr>
<!-- <tr><td></td><td></td><td></td><td></td><td></td><td></td></tr> -->
</table>