From f6b640be240d14ff992b96cdd27d644f3eee1318 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Tue, 11 Nov 2014 23:38:34 +0000 Subject: [PATCH] Make std::mem_fn work with varargs functions. * 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 | 16 ++ libstdc++-v3/include/std/functional | 227 ++++++------------ libstdc++-v3/include/std/type_traits | 3 + .../testsuite/20_util/bind/ref_neg.cc | 8 +- .../testsuite/20_util/bind/refqual.cc | 43 ++++ .../20_util/declval/requirements/1_neg.cc | 2 +- .../function_objects/mem_fn/refqual.cc | 2 + .../make_signed/requirements/typedefs_neg.cc | 4 +- .../requirements/typedefs_neg.cc | 4 +- 9 files changed, 151 insertions(+), 158 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/bind/refqual.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 46412780c96..f19aabc7e26 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,19 @@ +2014-11-11 Jonathan Wakely + + * 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 * testsuite/libstdc++-xmethods/associative-containers.cc: Add new diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index 25ec1b351b8..92489b7d4b9 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -512,113 +512,38 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) using __arity = integral_constant; }; - template - 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 - 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 \ + 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 \ + 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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::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 - result_type - _M_call(_Tp&& __object, const volatile _Class *, - _Args&&... __args) const - { - return (std::forward<_Tp>(__object).*_M_pmf) - (std::forward<_Args>(__args)...); - } - - template - 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 - 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 - using _RequireValidArgs2 - = _Require<_NotSame<_Class, _Tp>, _NotSame<_Class*, _Tp>, - _AllConvertible<_Pack<_Args...>, _ArgTypes>>; + template + friend struct _Bind_check_arity; - // Require each _Args to be convertible to corresponding _ArgTypes - // and require _Tp is _Class or derived from _Class - template - using _RequireValidArgs3 - = _Require, - _AllConvertible<_Pack<_Args...>, _ArgTypes>>; + // for varargs functions we just check the number of arguments, + // otherwise we also check they are convertible. + template + 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, _ArgTypes>>> + _CheckArgs<_Pack<_Args...>>>> result_type operator()(_Class& __object, _Args&&... __args) const { return (__object.*_M_pmf)(std::forward<_Args>(__args)...); } template, _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, _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, _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 _Traits::__lvalue, - _AllConvertible<_Pack<_Args...>, _ArgTypes>>> + = _Require, 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 + result_type + _M_call(_Tp&& __object, const volatile _Class *, + _Args&&... __args) const + { + return (std::forward<_Tp>(__object).*_M_pmf) + (std::forward<_Args>(__args)...); + } + + template + 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; + using _Varargs = false_type; + + template + 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 + struct _Bind_check_arity<_Ret (*)(_Args......), _BoundArgs...> + { + static_assert(sizeof...(_BoundArgs) >= sizeof...(_Args), + "Wrong number of arguments for function"); + }; + template 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 diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index b92bbf09287..cecc7dc2697 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -89,6 +89,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// The type used as a compile-time boolean with false value. typedef integral_constant false_type; + template + using __bool_constant = integral_constant; + // Meta programming helper types. template diff --git a/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc b/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc index 4e627cfaf48..7810968663d 100644 --- a/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc +++ b/libstdc++-v3/testsuite/20_util/bind/ref_neg.cc @@ -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 index 00000000000..76f4f5c4093 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/bind/refqual.cc @@ -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 +// . + +// { dg-options "-std=gnu++11" } + +#include +#include + +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(); +} diff --git a/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc b/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc index debcb28fd35..cdcbdbe87f7 100644 --- a/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc +++ b/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc @@ -19,7 +19,7 @@ // with this library; see the file COPYING3. If not see // . -// { dg-error "static assertion failed" "" { target *-*-* } 2201 } +// { dg-error "static assertion failed" "" { target *-*-* } 2204 } #include diff --git a/libstdc++-v3/testsuite/20_util/function_objects/mem_fn/refqual.cc b/libstdc++-v3/testsuite/20_util/function_objects/mem_fn/refqual.cc index 35a66e55410..4f3a64bacfa 100644 --- a/libstdc++-v3/testsuite/20_util/function_objects/mem_fn/refqual.cc +++ b/libstdc++-v3/testsuite/20_util/function_objects/mem_fn/refqual.cc @@ -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 ); } diff --git a/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc b/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc index aeef380ee93..b38ffdf87d8 100644 --- a/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc +++ b/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc @@ -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 } diff --git a/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc b/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc index ebfdc429444..d2e11a698a9 100644 --- a/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc +++ b/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc @@ -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 } -- 2.30.2