EricWF created this revision. EricWF added a reviewer: mclow.lists. EricWF added a subscriber: cfe-commits.
This patch fixes __not_null's detection of nullptr by breaking it down into 4 cases. 1. `__not_null(Tp const&)`: Default case. Tp is not null. 2. `__not_null(Tp* __ptr);` Case for pointers to functions. 3. `__not_null(_Ret _Class::* __ptr);` Case for pointers to members. 4. `__not_null(function<Tp> const&);`: Cases for other std::functions. http://reviews.llvm.org/D11111 Files: include/__functional_03 include/functional test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/F_nullptr.pass.cpp
Index: test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/F_nullptr.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/F_nullptr.pass.cpp @@ -0,0 +1,247 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// <functional> + +// class function<R(ArgTypes...)> + +// function(Fp); + +// Ensure that __not_null works for all function types. +// See https://llvm.org/bugs/show_bug.cgi?id=23589 + +//------------------------------------------------------------------------------ +// TESTING std::function<...>::__not_null(Callable) +// +// Concerns: +// 1) The call __not_null(Callable) is well formed and correct for each +// possible 'Callable' type category. These categories include: +// 1a) function pointers +// 1b) member function pointer +// 1c) member data pointer +// 1d) callable class type +// 1e) lambdas +// Categories 1a, 1b, and 1c are 'Nullable' types. Only objects of these +// types can be null. The other categories are not tested here. +// 3) '__not_null(Callable)' is well formed when the call signature includes +// varargs. +// 4) '__not_null(Callable)' works for Callable types with all aritys less +// than or equal to 3 in C++03. +// 5) '__not_null(Callable)' works when 'Callable' is a member function +// pointer to a cv or ref qualified function type. +// +// Plan: +// 1 For categories 1a, 1b and 1c define a set of +// 'Callable' objects for this category. This set should include examples +// of arity 0, 1, 2 and possible 3 including versions with varargs as the +// last parameter. +// +// 2 For each 'Callable' object in categories 1a, 1b and 1c do the following. +// +// 1 Define a type 'std::function<Sig>' as 'F' where 'Sig' is compatible with +// the signature of the 'Callable' object. +// +// 2 Create an object of type 'F' using a null pointer of type 'Callable'. +// Check that 'F.target<Callable>()' is null. +// +// 3 Create an object of type 'F' that is not null. Check that +// 'F.target<Callable>()' is not null and is equal to the original +// argument. + +#include <functional> +#include <type_traits> +#include <cassert> + +#include "test_macros.h" + +/////////////////////////////////////////////////////////////////////////////// +int foo() { return 42; } +int foo(int) { return 42; } +int foo(int, int) { return 42; } +int foo(int, int, int) { return 42; } + +int foo(...) { return 42; } +int foo(int, ...) { return 42; } +int foo(int, int, ...) { return 42; } +int foo(int, int, int, ...) { return 42; } + +/////////////////////////////////////////////////////////////////////////////// +struct MemFun03 { + int foo() { return 42; } + int foo() const { return 42; } + int foo() volatile { return 42; } + int foo() const volatile { return 42; } + + int foo(int) { return 42; } + int foo(int) const { return 42; } + int foo(int) volatile { return 42; } + int foo(int) const volatile { return 42; } + + int foo(int, int) { return 42; } + int foo(int, int) const { return 42; } + int foo(int, int) volatile { return 42; } + int foo(int, int) const volatile { return 42; } + + int foo(int, int, int) { return 42; } + int foo(int, int, int) const { return 42; } + int foo(int, int, int) volatile { return 42; } + int foo(int, int, int) const volatile { return 42; } + + int foo(...) { return 42; } + int foo(...) const { return 42; } + int foo(...) volatile { return 42; } + int foo(...) const volatile { return 42; } + + int foo(int, ...) { return 42; } + int foo(int, ...) const { return 42; } + int foo(int, ...) volatile { return 42; } + int foo(int, ...) const volatile { return 42; } + + int foo(int, int, ...) { return 42; } + int foo(int, int, ...) const { return 42; } + int foo(int, int, ...) volatile { return 42; } + int foo(int, int, ...) const volatile { return 42; } + + int foo(int, int, int, ...) { return 42; } + int foo(int, int, int, ...) const { return 42; } + int foo(int, int, int, ...) volatile { return 42; } + int foo(int, int, int, ...) const volatile { return 42; } +}; + +#if TEST_STD_VER >= 11 +struct MemFun11 { + int foo() & { return 42; } + int foo() const & { return 42; } + int foo() volatile & { return 42; } + int foo() const volatile & { return 42; } + + int foo(...) & { return 42; } + int foo(...) const & { return 42; } + int foo(...) volatile & { return 42; } + int foo(...) const volatile & { return 42; } + + int foo() && { return 42; } + int foo() const && { return 42; } + int foo() volatile && { return 42; } + int foo() const volatile && { return 42; } + + int foo(...) && { return 42; } + int foo(...) const && { return 42; } + int foo(...) volatile && { return 42; } + int foo(...) const volatile && { return 42; } +}; +#endif // TEST_STD_VER >= 11 + +struct MemData { + int foo; +}; + +// Create a non-null free function by taking the address of +// &static_cast<Tp&>(foo); +template <class Tp> +struct Creator { + static Tp create() { + return &foo; + } +}; + +// Create a non-null member pointer. +template <class Ret, class Class> +struct Creator<Ret Class::*> { + typedef Ret Class::*ReturnType; + static ReturnType create() { + return &Class::foo; + } +}; + +template <class TestFn, class Fn> +void test_imp() { + { // Check that the null value is detected + TestFn tf = nullptr; + std::function<Fn> f = tf; + assert(f.template target<TestFn>() == nullptr); + } + { // Check that the non-null value is detected. + TestFn tf = Creator<TestFn>::create(); + assert(tf != nullptr); + std::function<Fn> f = tf; + assert(f.template target<TestFn>() != nullptr); + assert(*f.template target<TestFn>() == tf); + } +} + +void test_func() { + test_imp<int(*)(), int()>(); + test_imp<int(*)(...), int()>(); + test_imp<int(*)(int), int(int)>(); + test_imp<int(*)(int, ...), int(int)>(); + test_imp<int(*)(int, int), int(int, int)>(); + test_imp<int(*)(int, int, ...), int(int, int)>(); + test_imp<int(*)(int, int, int), int(int, int, int)>(); + test_imp<int(*)(int, int, int, ...), int(int, int, int)>(); +} + +void test_mf() { + test_imp<int(MemFun03::*)(), int(MemFun03&)>(); + test_imp<int(MemFun03::*)(...), int(MemFun03&)>(); + test_imp<int(MemFun03::*)() const, int(MemFun03&)>(); + test_imp<int(MemFun03::*)(...) const, int(MemFun03&)>(); + test_imp<int(MemFun03::*)() volatile, int(MemFun03&)>(); + test_imp<int(MemFun03::*)(...) volatile, int(MemFun03&)>(); + test_imp<int(MemFun03::*)() const volatile, int(MemFun03&)>(); + test_imp<int(MemFun03::*)(...) const volatile, int(MemFun03&)>(); + + test_imp<int(MemFun03::*)(int), int(MemFun03&, int)>(); + test_imp<int(MemFun03::*)(int, ...), int(MemFun03&, int)>(); + test_imp<int(MemFun03::*)(int) const, int(MemFun03&, int)>(); + test_imp<int(MemFun03::*)(int, ...) const, int(MemFun03&, int)>(); + test_imp<int(MemFun03::*)(int) volatile, int(MemFun03&, int)>(); + test_imp<int(MemFun03::*)(int, ...) volatile, int(MemFun03&, int)>(); + test_imp<int(MemFun03::*)(int) const volatile, int(MemFun03&, int)>(); + test_imp<int(MemFun03::*)(int, ...) const volatile, int(MemFun03&, int)>(); + + test_imp<int(MemFun03::*)(int, int), int(MemFun03&, int, int)>(); + test_imp<int(MemFun03::*)(int, int, ...), int(MemFun03&, int, int)>(); + test_imp<int(MemFun03::*)(int, int) const, int(MemFun03&, int, int)>(); + test_imp<int(MemFun03::*)(int, int, ...) const, int(MemFun03&, int, int)>(); + test_imp<int(MemFun03::*)(int, int) volatile, int(MemFun03&, int, int)>(); + test_imp<int(MemFun03::*)(int, int, ...) volatile, int(MemFun03&, int, int)>(); + test_imp<int(MemFun03::*)(int, int) const volatile, int(MemFun03&, int, int)>(); + test_imp<int(MemFun03::*)(int, int, ...) const volatile, int(MemFun03&, int, int)>(); + +#if TEST_STD_VER >= 11 + test_imp<int(MemFun11::*)() &, int(MemFun11&)>(); + test_imp<int(MemFun11::*)(...) &, int(MemFun11&)>(); + test_imp<int(MemFun11::*)() const &, int(MemFun11&)>(); + test_imp<int(MemFun11::*)(...) const &, int(MemFun11&)>(); + test_imp<int(MemFun11::*)() volatile &, int(MemFun11&)>(); + test_imp<int(MemFun11::*)(...) volatile &, int(MemFun11&)>(); + test_imp<int(MemFun11::*)() const volatile &, int(MemFun11&)>(); + test_imp<int(MemFun11::*)(...) const volatile &, int(MemFun11&)>(); + + test_imp<int(MemFun11::*)() &&, int(MemFun11&&)>(); + test_imp<int(MemFun11::*)(...) &&, int(MemFun11&&)>(); + test_imp<int(MemFun11::*)() const &&, int(MemFun11&&)>(); + test_imp<int(MemFun11::*)(...) const &&, int(MemFun11&&)>(); + test_imp<int(MemFun11::*)() volatile &&, int(MemFun11&&)>(); + test_imp<int(MemFun11::*)(...) volatile &&, int(MemFun11&&)>(); + test_imp<int(MemFun11::*)() const volatile &&, int(MemFun11&&)>(); + test_imp<int(MemFun11::*)(...) const volatile &&, int(MemFun11&&)>(); +#endif +} + +void test_md() { + test_imp<int MemData::*, int(MemData&)>(); +} + +int main() { + test_func(); + test_mf(); + test_md(); +} Index: include/functional =================================================================== --- include/functional +++ include/functional @@ -1234,6 +1234,26 @@ mem_fun_ref(_Sp (_Tp::*__f)(_Ap) const) {return const_mem_fun1_ref_t<_Sp,_Tp,_Ap>(__f);} +template<class _Fp> class _LIBCPP_TYPE_VIS_ONLY function; // undefined + +namespace __function { + template <class _Fp> + _LIBCPP_INLINE_VISIBILITY + bool __not_null(_Fp const&) { return true; } + + template <class _Fp> + _LIBCPP_INLINE_VISIBILITY + bool __not_null(_Fp* __ptr) { return __ptr; } + + template <class _Ret, class _Class> + _LIBCPP_INLINE_VISIBILITY + bool __not_null(_Ret _Class::*__ptr) { return __ptr; } + + template <class _Fp> + _LIBCPP_INLINE_VISIBILITY + bool __not_null(function<_Fp> const& __f) { return !!__f; } +} + #ifdef _LIBCPP_HAS_NO_VARIADICS #include <__functional_03> @@ -1278,8 +1298,6 @@ { }; -template<class _Fp> class _LIBCPP_TYPE_VIS_ONLY function; // undefined - namespace __function { @@ -1440,28 +1458,6 @@ typename aligned_storage<3*sizeof(void*)>::type __buf_; __base* __f_; - template <class _Fp> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(const _Fp&) {return true;} - template <class _R2, class ..._Ap> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(_R2 (*__p)(_Ap...)) {return __p;} - template <class _R2, class _Cp, class ..._Ap> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(_R2 (_Cp::*__p)(_Ap...)) {return __p;} - template <class _R2, class _Cp, class ..._Ap> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(_R2 (_Cp::*__p)(_Ap...) const) {return __p;} - template <class _R2, class _Cp, class ..._Ap> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(_R2 (_Cp::*__p)(_Ap...) volatile) {return __p;} - template <class _R2, class _Cp, class ..._Ap> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(_R2 (_Cp::*__p)(_Ap...) const volatile) {return __p;} - template <class _R2, class ..._Ap> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(const function<_R2(_Ap...)>& __p) {return !!__p;} - template <class _Fp, bool = !is_same<_Fp, function>::value && __invokable<_Fp&, _ArgTypes...>::value> struct __callable; @@ -1626,7 +1622,7 @@ >::type*) : __f_(0) { - if (__not_null(__f)) + if (__function::__not_null(__f)) { typedef __function::__func<_Fp, allocator<_Fp>, _Rp(_ArgTypes...)> _FF; if (sizeof(_FF) <= sizeof(__buf_) && is_nothrow_copy_constructible<_Fp>::value) @@ -1653,7 +1649,7 @@ : __f_(0) { typedef allocator_traits<_Alloc> __alloc_traits; - if (__not_null(__f)) + if (__function::__not_null(__f)) { typedef __function::__func<_Fp, _Alloc, _Rp(_ArgTypes...)> _FF; typedef typename __rebind_alloc_helper<__alloc_traits, _FF>::type _Ap; Index: include/__functional_03 =================================================================== --- include/__functional_03 +++ include/__functional_03 @@ -203,8 +203,6 @@ { }; -template<class _Fp> class _LIBCPP_TYPE_VIS_ONLY function; // undefined - namespace __function { @@ -662,15 +660,6 @@ aligned_storage<3*sizeof(void*)>::type __buf_; __base* __f_; - template <class _Fp> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(const _Fp&) {return true;} - template <class _R2> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(_R2 (*__p)()) {return __p;} - template <class _R2> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(const function<_R2()>& __p) {return __p;} public: typedef _Rp result_type; @@ -769,7 +758,7 @@ typename enable_if<!is_integral<_Fp>::value>::type*) : __f_(0) { - if (__not_null(__f)) + if (__function::__not_null(__f)) { typedef __function::__func<_Fp, allocator<_Fp>, _Rp()> _FF; if (sizeof(_FF) <= sizeof(__buf_)) @@ -796,7 +785,7 @@ : __f_(0) { typedef allocator_traits<_Alloc> __alloc_traits; - if (__not_null(__f)) + if (__function::__not_null(__f)) { typedef __function::__func<_Fp, _Alloc, _Rp()> _FF; if (sizeof(_FF) <= sizeof(__buf_)) @@ -947,27 +936,6 @@ aligned_storage<3*sizeof(void*)>::type __buf_; __base* __f_; - template <class _Fp> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(const _Fp&) {return true;} - template <class _R2, class _B0> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(_R2 (*__p)(_B0)) {return __p;} - template <class _R2, class _Cp> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(_R2 (_Cp::*__p)()) {return __p;} - template <class _R2, class _Cp> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(_R2 (_Cp::*__p)() const) {return __p;} - template <class _R2, class _Cp> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(_R2 (_Cp::*__p)() volatile) {return __p;} - template <class _R2, class _Cp> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(_R2 (_Cp::*__p)() const volatile) {return __p;} - template <class _R2, class _B0> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(const function<_R2(_B0)>& __p) {return __p;} public: typedef _Rp result_type; @@ -1066,7 +1034,7 @@ typename enable_if<!is_integral<_Fp>::value>::type*) : __f_(0) { - if (__not_null(__f)) + if (__function::__not_null(__f)) { typedef __function::__func<_Fp, allocator<_Fp>, _Rp(_A0)> _FF; if (sizeof(_FF) <= sizeof(__buf_)) @@ -1093,7 +1061,7 @@ : __f_(0) { typedef allocator_traits<_Alloc> __alloc_traits; - if (__not_null(__f)) + if (__function::__not_null(__f)) { typedef __function::__func<_Fp, _Alloc, _Rp(_A0)> _FF; if (sizeof(_FF) <= sizeof(__buf_)) @@ -1244,27 +1212,6 @@ aligned_storage<3*sizeof(void*)>::type __buf_; __base* __f_; - template <class _Fp> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(const _Fp&) {return true;} - template <class _R2, class _B0, class _B1> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(_R2 (*__p)(_B0, _B1)) {return __p;} - template <class _R2, class _Cp, class _B1> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(_R2 (_Cp::*__p)(_B1)) {return __p;} - template <class _R2, class _Cp, class _B1> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(_R2 (_Cp::*__p)(_B1) const) {return __p;} - template <class _R2, class _Cp, class _B1> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(_R2 (_Cp::*__p)(_B1) volatile) {return __p;} - template <class _R2, class _Cp, class _B1> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(_R2 (_Cp::*__p)(_B1) const volatile) {return __p;} - template <class _R2, class _B0, class _B1> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(const function<_R2(_B0, _B1)>& __p) {return __p;} public: typedef _Rp result_type; @@ -1363,7 +1310,7 @@ typename enable_if<!is_integral<_Fp>::value>::type*) : __f_(0) { - if (__not_null(__f)) + if (__function::__not_null(__f)) { typedef __function::__func<_Fp, allocator<_Fp>, _Rp(_A0, _A1)> _FF; if (sizeof(_FF) <= sizeof(__buf_)) @@ -1390,7 +1337,7 @@ : __f_(0) { typedef allocator_traits<_Alloc> __alloc_traits; - if (__not_null(__f)) + if (__function::__not_null(__f)) { typedef __function::__func<_Fp, _Alloc, _Rp(_A0, _A1)> _FF; if (sizeof(_FF) <= sizeof(__buf_)) @@ -1540,27 +1487,6 @@ aligned_storage<3*sizeof(void*)>::type __buf_; __base* __f_; - template <class _Fp> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(const _Fp&) {return true;} - template <class _R2, class _B0, class _B1, class _B2> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(_R2 (*__p)(_B0, _B1, _B2)) {return __p;} - template <class _R2, class _Cp, class _B1, class _B2> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(_R2 (_Cp::*__p)(_B1, _B2)) {return __p;} - template <class _R2, class _Cp, class _B1, class _B2> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(_R2 (_Cp::*__p)(_B1, _B2) const) {return __p;} - template <class _R2, class _Cp, class _B1, class _B2> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(_R2 (_Cp::*__p)(_B1, _B2) volatile) {return __p;} - template <class _R2, class _Cp, class _B1, class _B2> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(_R2 (_Cp::*__p)(_B1, _B2) const volatile) {return __p;} - template <class _R2, class _B0, class _B1, class _B2> - _LIBCPP_INLINE_VISIBILITY - static bool __not_null(const function<_R2(_B0, _B1, _B2)>& __p) {return __p;} public: typedef _Rp result_type; @@ -1660,7 +1586,7 @@ typename enable_if<!is_integral<_Fp>::value>::type*) : __f_(0) { - if (__not_null(__f)) + if (__function::__not_null(__f)) { typedef __function::__func<_Fp, allocator<_Fp>, _Rp(_A0, _A1, _A2)> _FF; if (sizeof(_FF) <= sizeof(__buf_)) @@ -1687,7 +1613,7 @@ : __f_(0) { typedef allocator_traits<_Alloc> __alloc_traits; - if (__not_null(__f)) + if (__function::__not_null(__f)) { typedef __function::__func<_Fp, _Alloc, _Rp(_A0, _A1, _A2)> _FF; if (sizeof(_FF) <= sizeof(__buf_))
_______________________________________________ cfe-commits mailing list cfe-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits