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

Reply via email to