Make std::mem_fn work with varargs functions.
authorJonathan Wakely <jwakely@redhat.com>
Tue, 11 Nov 2014 23:38:34 +0000 (23:38 +0000)
committerJonathan Wakely <redi@gcc.gnu.org>
Tue, 11 Nov 2014 23:38:34 +0000 (23:38 +0000)
* include/std/functional (_Mem_fn_traits): Add partial specializations
for varargs functions.
(_Mem_fn_base): Do not check arguments are convertible for varargs.
(_Bind_check_arity): Add partial specializations for varargs functions.
* include/std/type_traits (__bool_constant): Add alias template.
* testsuite/20_util/bind/ref_neg.cc: Adjust dg-error.
* testsuite/20_util/bind/refqual.cc: New, test ref-qualifiers.
* testsuite/20_util/declval/requirements/1_neg.cc: Adjust dg-error.
* testsuite/20_util/function_objects/mem_fn/refqual.cc: Test varargs.
* testsuite/20_util/make_signed/requirements/typedefs_neg.cc: Adjust
dg-error.
* testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc: Adjust
dg-error.

From-SVN: r217393

libstdc++-v3/ChangeLog
libstdc++-v3/include/std/functional
libstdc++-v3/include/std/type_traits
libstdc++-v3/testsuite/20_util/bind/ref_neg.cc
libstdc++-v3/testsuite/20_util/bind/refqual.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc
libstdc++-v3/testsuite/20_util/function_objects/mem_fn/refqual.cc
libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc
libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc

index 4641278..f19aabc 100644 (file)
@@ -1,3 +1,19 @@
+2014-11-11  Jonathan Wakely  <jwakely@redhat.com>
+
+       * include/std/functional (_Mem_fn_traits): Add partial specializations
+       for varargs functions.
+       (_Mem_fn_base): Do not check arguments are convertible for varargs.
+       (_Bind_check_arity): Add partial specializations for varargs functions.
+       * include/std/type_traits (__bool_constant): Add alias template.
+       * testsuite/20_util/bind/ref_neg.cc: Adjust dg-error.
+       * testsuite/20_util/bind/refqual.cc: New, test ref-qualifiers.
+       * testsuite/20_util/declval/requirements/1_neg.cc: Adjust dg-error.
+       * testsuite/20_util/function_objects/mem_fn/refqual.cc: Test varargs.
+       * testsuite/20_util/make_signed/requirements/typedefs_neg.cc: Adjust
+       dg-error.
+       * testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc: Adjust
+       dg-error.
+
 2014-11-11  Siva Chandra Reddy  <sivachandra@google.com>
 
        * testsuite/libstdc++-xmethods/associative-containers.cc: Add new
index 25ec1b3..92489b7 100644 (file)
@@ -512,113 +512,38 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type)
       using __arity = integral_constant<size_t, sizeof...(_ArgTypes)>;
     };
 
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...)>
-    : _Mem_fn_traits_base<_Res, _Class, _ArgTypes...>
-    {
-      using __pmf_type  = _Res (_Class::*)(_ArgTypes...);
-      using __lvalue = true_type;
-      using __rvalue = true_type;
-    };
-
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) const>
-    : _Mem_fn_traits_base<_Res, const _Class, _ArgTypes...>
-    {
-      using __pmf_type  = _Res (_Class::*)(_ArgTypes...) const;
-      using __lvalue = true_type;
-      using __rvalue = true_type;
+#define _GLIBCXX_MEM_FN_TRAITS2(_CV, _REF, _LVAL, _RVAL)               \
+  template<typename _Res, typename _Class, typename... _ArgTypes>      \
+    struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) _CV _REF>     \
+    : _Mem_fn_traits_base<_Res, _CV _Class, _ArgTypes...>              \
+    {                                                                  \
+      using __pmf_type  = _Res (_Class::*)(_ArgTypes...) _CV _REF;     \
+      using __lvalue = _LVAL;                                          \
+      using __rvalue = _RVAL;                                          \
+      using __vararg = false_type;                                     \
+    };                                                                 \
+  template<typename _Res, typename _Class, typename... _ArgTypes>      \
+    struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes... ...) _CV _REF> \
+    : _Mem_fn_traits_base<_Res, _CV _Class, _ArgTypes...>              \
+    {                                                                  \
+      using __pmf_type  = _Res (_Class::*)(_ArgTypes... ...) _CV _REF; \
+      using __lvalue = _LVAL;                                          \
+      using __rvalue = _RVAL;                                          \
+      using __vararg = true_type;                                      \
     };
 
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) volatile>
-    : _Mem_fn_traits_base<_Res, volatile _Class, _ArgTypes...>
-    {
-      using __pmf_type  = _Res (_Class::*)(_ArgTypes...) volatile;
-      using __lvalue = true_type;
-      using __rvalue = true_type;
-    };
+#define _GLIBCXX_MEM_FN_TRAITS(_REF, _LVAL, _RVAL)             \
+  _GLIBCXX_MEM_FN_TRAITS2(             , _REF, _LVAL, _RVAL)   \
+  _GLIBCXX_MEM_FN_TRAITS2(const                , _REF, _LVAL, _RVAL)   \
+  _GLIBCXX_MEM_FN_TRAITS2(volatile     , _REF, _LVAL, _RVAL)   \
+  _GLIBCXX_MEM_FN_TRAITS2(const volatile, _REF, _LVAL, _RVAL)
 
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) const volatile>
-    : _Mem_fn_traits_base<_Res, const volatile _Class, _ArgTypes...>
-    {
-      using __pmf_type  = _Res (_Class::*)(_ArgTypes...) const volatile;
-      using __lvalue = true_type;
-      using __rvalue = true_type;
-    };
+_GLIBCXX_MEM_FN_TRAITS( , true_type, true_type)
+_GLIBCXX_MEM_FN_TRAITS(&, true_type, false_type)
+_GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
 
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...)&>
-    : _Mem_fn_traits_base<_Res, _Class, _ArgTypes...>
-    {
-      using __pmf_type  = _Res (_Class::*)(_ArgTypes...)&;
-      using __lvalue = true_type;
-      using __rvalue = false_type;
-    };
-
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) const&>
-    : _Mem_fn_traits_base<_Res, const _Class, _ArgTypes...>
-    {
-      using __pmf_type  = _Res (_Class::*)(_ArgTypes...) const&;
-      using __lvalue = true_type;
-      using __rvalue = false_type;
-    };
-
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) volatile&>
-    : _Mem_fn_traits_base<_Res, volatile _Class, _ArgTypes...>
-    {
-      using __pmf_type  = _Res (_Class::*)(_ArgTypes...) volatile&;
-      using __lvalue = true_type;
-      using __rvalue = false_type;
-    };
-
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) const volatile&>
-    : _Mem_fn_traits_base<_Res, const volatile _Class, _ArgTypes...>
-    {
-      using __pmf_type  = _Res (_Class::*)(_ArgTypes...) const volatile&;
-      using __lvalue = true_type;
-      using __rvalue = false_type;
-    };
-
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...)&&>
-    : _Mem_fn_traits_base<_Res, _Class, _ArgTypes...>
-    {
-      using __pmf_type  = _Res (_Class::*)(_ArgTypes...)&&;
-      using __lvalue = false_type;
-      using __rvalue = true_type;
-    };
-
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) const&&>
-    : _Mem_fn_traits_base<_Res, const _Class, _ArgTypes...>
-    {
-      using __pmf_type  = _Res (_Class::*)(_ArgTypes...) const&&;
-      using __lvalue = false_type;
-      using __rvalue = true_type;
-    };
-
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) volatile&&>
-    : _Mem_fn_traits_base<_Res, volatile _Class, _ArgTypes...>
-    {
-      using __pmf_type  = _Res (_Class::*)(_ArgTypes...) volatile&&;
-      using __lvalue = false_type;
-      using __rvalue = true_type;
-    };
-
-  template<typename _Res, typename _Class, typename... _ArgTypes>
-    struct _Mem_fn_traits<_Res (_Class::*)(_ArgTypes...) const volatile&&>
-    : _Mem_fn_traits_base<_Res, const volatile _Class, _ArgTypes...>
-    {
-      using __pmf_type  = _Res (_Class::*)(_ArgTypes...) const volatile&&;
-      using __lvalue = false_type;
-      using __rvalue = true_type;
-    };
+#undef _GLIBCXX_MEM_FN_TRAITS
+#undef _GLIBCXX_MEM_FN_TRAITS2
 
   template<typename _MemFunPtr,
           bool __is_mem_fn = is_member_function_pointer<_MemFunPtr>::value>
@@ -627,62 +552,40 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type)
     {
       using _Traits = _Mem_fn_traits<_MemFunPtr>;
 
-    public:
-      using result_type = typename _Traits::__result_type;
-      using _Arity = typename _Traits::__arity;
-
-    private:
       using _Class = typename _Traits::__class_type;
       using _ArgTypes = typename _Traits::__arg_types;
       using _Pmf = typename _Traits::__pmf_type;
 
-      template<typename _Tp, typename... _Args>
-       result_type
-       _M_call(_Tp&& __object, const volatile _Class *,
-               _Args&&... __args) const
-       {
-         return (std::forward<_Tp>(__object).*_M_pmf)
-           (std::forward<_Args>(__args)...);
-       }
-
-      template<typename _Tp, typename... _Args>
-       result_type
-       _M_call(_Tp&& __ptr, const volatile void *, _Args&&... __args) const
-       { return ((*__ptr).*_M_pmf)(std::forward<_Args>(__args)...); }
-
-      // Require each _Args to be convertible to corresponding _ArgTypes
-      template<typename... _Args>
-       using _RequireValidArgs
-         = _Require<_AllConvertible<_Pack<_Args...>, _ArgTypes>>;
+      using _Arity = typename _Traits::__arity;
+      using _Varargs = typename _Traits::__vararg;
 
-      // Require each _Args to be convertible to corresponding _ArgTypes
-      // and require _Tp is not _Class, _Class& or _Class*
-      template<typename _Tp, typename... _Args>
-       using _RequireValidArgs2
-         = _Require<_NotSame<_Class, _Tp>, _NotSame<_Class*, _Tp>,
-                    _AllConvertible<_Pack<_Args...>, _ArgTypes>>;
+      template<typename _Func, typename... _BoundArgs>
+       friend struct _Bind_check_arity;
 
-      // Require each _Args to be convertible to corresponding _ArgTypes
-      // and require _Tp is _Class or derived from _Class
-      template<typename _Tp, typename... _Args>
-       using _RequireValidArgs3
-         = _Require<is_base_of<_Class, _Tp>,
-                    _AllConvertible<_Pack<_Args...>, _ArgTypes>>;
+      // for varargs functions we just check the number of arguments,
+      // otherwise we also check they are convertible.
+      template<typename _Args>
+       using _CheckArgs = typename conditional<_Varargs::value,
+         __bool_constant<(_Args::value >= _ArgTypes::value)>,
+         _AllConvertible<_Args, _ArgTypes>
+       >::type;
 
     public:
+      using result_type = typename _Traits::__result_type;
+
       explicit _Mem_fn_base(_Pmf __pmf) : _M_pmf(__pmf) { }
 
       // Handle objects
       template<typename... _Args, typename _Req
                = _Require<typename _Traits::__lvalue,
-                          _AllConvertible<_Pack<_Args...>, _ArgTypes>>>
+                          _CheckArgs<_Pack<_Args...>>>>
        result_type
        operator()(_Class& __object, _Args&&... __args) const
        { return (__object.*_M_pmf)(std::forward<_Args>(__args)...); }
 
       template<typename... _Args, typename _Req
                = _Require<typename _Traits::__rvalue,
-                          _AllConvertible<_Pack<_Args...>, _ArgTypes>>>
+                          _CheckArgs<_Pack<_Args...>>>>
        result_type
        operator()(_Class&& __object, _Args&&... __args) const
        {
@@ -692,16 +595,15 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type)
       // Handle pointers
       template<typename... _Args, typename _Req
                = _Require<typename _Traits::__lvalue,
-                          _AllConvertible<_Pack<_Args...>, _ArgTypes>>>
+                          _CheckArgs<_Pack<_Args...>>>>
        result_type
        operator()(_Class* __object, _Args&&... __args) const
        { return (__object->*_M_pmf)(std::forward<_Args>(__args)...); }
 
       // Handle smart pointers, references and pointers to derived
-      // TODO how to constrain to lvalue/rvalue here? constrain _M_call?
       template<typename _Tp, typename... _Args, typename _Req
                = _Require<_NotSame<_Class, _Tp>, _NotSame<_Class*, _Tp>,
-                          _AllConvertible<_Pack<_Args...>, _ArgTypes>>>
+                          _CheckArgs<_Pack<_Args...>>>>
        result_type
        operator()(_Tp&& __object, _Args&&... __args) const
        {
@@ -711,14 +613,27 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type)
 
       // Handle reference wrappers
       template<typename _Tp, typename... _Args, typename _Req
-               = _Require<is_base_of<_Class, _Tp>,
-                          typename _Traits::__lvalue,
-                          _AllConvertible<_Pack<_Args...>, _ArgTypes>>>
+               = _Require<is_base_of<_Class, _Tp>, typename _Traits::__lvalue,
+                          _CheckArgs<_Pack<_Args...>>>>
        result_type
        operator()(reference_wrapper<_Tp> __ref, _Args&&... __args) const
        { return operator()(__ref.get(), std::forward<_Args>(__args)...); }
 
     private:
+      template<typename _Tp, typename... _Args>
+       result_type
+       _M_call(_Tp&& __object, const volatile _Class *,
+               _Args&&... __args) const
+       {
+         return (std::forward<_Tp>(__object).*_M_pmf)
+           (std::forward<_Args>(__args)...);
+       }
+
+      template<typename _Tp, typename... _Args>
+       result_type
+       _M_call(_Tp&& __ptr, const volatile void *, _Args&&... __args) const
+       { return ((*__ptr).*_M_pmf)(std::forward<_Args>(__args)...); }
+
       _Pmf _M_pmf;
     };
 
@@ -750,9 +665,13 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type)
        -> decltype((*__ptr).*std::declval<__pm_type&>())
        { return (*__ptr).*_M_pm; }
 
-    public:
       using _Arity = integral_constant<size_t, 0>;
+      using _Varargs = false_type;
+
+      template<typename _Func, typename... _BoundArgs>
+       friend struct _Bind_check_arity;
 
+    public:
       explicit
       _Mem_fn_base(_Res _Class::*__pm) noexcept : _M_pm(__pm) { }
 
@@ -1493,12 +1412,22 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type)
                    "Wrong number of arguments for function");
     };
 
+  template<typename _Ret, typename... _Args, typename... _BoundArgs>
+    struct _Bind_check_arity<_Ret (*)(_Args......), _BoundArgs...>
+    {
+      static_assert(sizeof...(_BoundArgs) >= sizeof...(_Args),
+                   "Wrong number of arguments for function");
+    };
+
   template<typename _Tp, typename _Class, typename... _BoundArgs>
     struct _Bind_check_arity<_Tp _Class::*, _BoundArgs...>
     {
       using _Arity = typename _Mem_fn<_Tp _Class::*>::_Arity;
-      static_assert(sizeof...(_BoundArgs) == _Arity::value + 1,
-                   "Wrong number of arguments for pointer-to-member");
+      using _Varargs = typename _Mem_fn<_Tp _Class::*>::_Varargs;
+      static_assert(_Varargs::value
+                   ? sizeof...(_BoundArgs) >= _Arity::value + 1
+                   : sizeof...(_BoundArgs) == _Arity::value + 1,
+                   "Wrong number of arguments for pointer-to-member");
     };
 
   // Trait type used to remove std::bind() from overload set via SFINAE
index b92bbf0..cecc7dc 100644 (file)
@@ -89,6 +89,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// The type used as a compile-time boolean with false value.
   typedef integral_constant<bool, false>    false_type;
 
+  template<bool __v>
+    using __bool_constant = integral_constant<bool, __v>;
+
   // Meta programming helper types.
 
   template<bool, typename, typename>
index 4e627cf..7810968 100644 (file)
@@ -30,10 +30,10 @@ void test01()
 {
   const int dummy = 0;
   std::bind(&inc, _1)(0);               // { dg-error  "no match" }
-  // { dg-error "rvalue|const" "" { target *-*-* } 1207 }
-  // { dg-error "rvalue|const" "" { target *-*-* } 1221 }
-  // { dg-error "rvalue|const" "" { target *-*-* } 1235 }
-  // { dg-error "rvalue|const" "" { target *-*-* } 1249 }
+  // { dg-error "rvalue|const" "" { target *-*-* } 1126 }
+  // { dg-error "rvalue|const" "" { target *-*-* } 1140 }
+  // { dg-error "rvalue|const" "" { target *-*-* } 1154 }
+  // { dg-error "rvalue|const" "" { target *-*-* } 1168 }
   std::bind(&inc, std::ref(dummy))();  // { dg-error  "no match" }
 }
 
diff --git a/libstdc++-v3/testsuite/20_util/bind/refqual.cc b/libstdc++-v3/testsuite/20_util/bind/refqual.cc
new file mode 100644 (file)
index 0000000..76f4f5c
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright (C) 2014 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++11" }
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+struct X
+{
+  int f() const& { return 0; }
+  int g(int i, ...)& { return i; }
+};
+
+void
+test01()
+{
+  X x;
+  auto b = std::bind(&X::f, &x);
+  VERIFY( b() == 0 );
+  auto bb = std::bind(&X::g, &x, 1, 2);
+  VERIFY( bb() == 1 );
+}
+
+int
+main()
+{
+  test01();
+}
index debcb28..cdcbdbe 100644 (file)
@@ -19,7 +19,7 @@
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-// { dg-error "static assertion failed" "" { target *-*-* } 2201 }
+// { dg-error "static assertion failed" "" { target *-*-* } 2204 }
 
 #include <utility>
 
index 35a66e5..4f3a64b 100644 (file)
@@ -24,6 +24,7 @@ struct Foo
 {
   void r()&& { }
   int l() const& { return 0; }
+  void lv(int, ...)& { }
 };
 
 void test01()
@@ -31,4 +32,5 @@ void test01()
   Foo f;
   int i = std::mem_fn(&Foo::l)( f );
   std::mem_fn(&Foo::r)( std::move(f) );
+  std::mem_fn(&Foo::lv)( f, 1, 2, 3 );
 }
index aeef380..b38ffdf 100644 (file)
@@ -48,5 +48,5 @@ void test01()
 // { dg-error "required from here" "" { target *-*-* } 40 }
 // { dg-error "required from here" "" { target *-*-* } 42 }
 
-// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1866 }
-// { dg-error "declaration of" "" { target *-*-* } 1830 }
+// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1869 }
+// { dg-error "declaration of" "" { target *-*-* } 1833 }
index ebfdc42..d2e11a6 100644 (file)
@@ -48,5 +48,5 @@ void test01()
 // { dg-error "required from here" "" { target *-*-* } 40 }
 // { dg-error "required from here" "" { target *-*-* } 42 }
 
-// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1754 }
-// { dg-error "declaration of" "" { target *-*-* } 1718 }
+// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1757 }
+// { dg-error "declaration of" "" { target *-*-* } 1721 }