From patchwork Tue Nov 11 23:38:44 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 409711 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 49106140170 for ; Wed, 12 Nov 2014 10:38:58 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=Pzvl3b2Rth3VpG/dQxUQx2/zBiXt9t8HhLI7qeWz34NT7aPVsTOcb 7eJzmAODV6e7QZg4xLVNxuZ8wjAs8T/VPCGAitJwJ8rkTUQ5mwjj7Hq+JBpDv/6N t6fPGDU05sS0A0gUK9H3w0k0SvcDzcE2+bcAa6k6EREG4SW2oH5TCs= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=irNP0/vQFTisyCJja5vf3ab4zro=; b=qGvs0IciGuj7rRr3o858 EXRZM4ny5mAcc6b12yHzU2a1ucgcOUlmPww/KRLTRjYmY6v8VelvzYRe5wbP9FTq +U+4HGiQs1YF6ENqmT4oaLtESi637viLg3tL/QvEiBqaIPJsISTV0IwuBqDWnaC3 9l46gIOEPQc494YmeoYwdSI= Received: (qmail 13149 invoked by alias); 11 Nov 2014 23:38:50 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 13127 invoked by uid 89); 11 Nov 2014 23:38:49 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.4 required=5.0 tests=AWL, BAYES_20, RP_MATCHES_RCVD, SPF_HELO_PASS, SPF_PASS autolearn=ham version=3.3.2 X-Spam-User: qpsmtpd, 2 recipients X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Tue, 11 Nov 2014 23:38:47 +0000 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id sABNcj6g029329 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 11 Nov 2014 18:38:46 -0500 Received: from localhost (ovpn-116-136.ams2.redhat.com [10.36.116.136]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id sABNcicD028316; Tue, 11 Nov 2014 18:38:45 -0500 Date: Tue, 11 Nov 2014 23:38:44 +0000 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [patch] add varargs support to std::mem_fn Message-ID: <20141111233844.GO5191@redhat.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.23 (2014-03-12) My recent patch to add ref-qualifier support to std::mem_fn didn't cover C-style varargs functions (as opposed to C++ variadic templates, which work fine). Rather than double the number of partial specializations this generates them using a macro. The arity-checking needs to be adjusted to allow for additional arguments being passed through the ellipsis. This also adds a __bool_constant alias which I've been toying with adding for some time. LEWG are in favour of adding std::bool_constant to C++17 so adding __bool_constant now means we can use it even in C++11 mode. std::reference_wrapper still doesn't define the required typedefs when it wraps a pointer to ref-qualified member function, but that will have to wait for now. At some point we'll also need to implement the std::invoke() function that has been voted into C++17 and we might want to refactor all this code again. Tested x86_64-linux, committed to trunk. commit 07591983a7880e2370fbc10020e0d9cdfaa86678 Author: Jonathan Wakely Date: Tue Nov 11 13:44:45 2014 +0000 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. diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index 25ec1b3..92489b7 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 b92bbf0..cecc7dc 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 4e627cf..7810968 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 0000000..76f4f5c --- /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 debcb28..cdcbdbe 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 35a66e5..4f3a64b 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 aeef380..b38ffdf 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 ebfdc42..d2e11a6 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 }