From patchwork Thu Jan 12 14:29:53 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 91166 Delivered-To: patch@linaro.org Received: by 10.140.20.99 with SMTP id 90csp1648283qgi; Thu, 12 Jan 2017 06:31:01 -0800 (PST) X-Received: by 10.98.55.131 with SMTP id e125mr16976143pfa.58.1484231461299; Thu, 12 Jan 2017 06:31:01 -0800 (PST) Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id h189si9450545pfb.15.2017.01.12.06.31.00 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 12 Jan 2017 06:31:01 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-return-445968-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org; spf=pass (google.com: domain of gcc-patches-return-445968-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) smtp.mailfrom=gcc-patches-return-445968-patch=linaro.org@gcc.gnu.org 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=bOhsGIsvyDHBHmp9mGLL9+KfF5ARx5C1gMdY3yjMAhMkVdqwJXY9F AKlOHMglKAaxLGREua2QzaOlkuO44LuhQNjM8R2B37sNNyqsWB03+loER8lsNNmT 3DrG+bXVi38dRUGZzB2hk9OKElWe+5t0S9hIrvWGurFQyuNi0D9rCs= 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=bnT146Zx5oe/ofod+D56fybzEU4=; b=x15J41z3hGr6K59XvXEc 7eiJDegU0mnBRY3I/DtVDub8BDuvHE7/K3/TPRnXOPSp26XlrIbnvleMS8hMWC66 OnzkO/bsfftXcvcg+i4CgEPsZdt3vMzmT7GZhDekDfSZUySFvH0M16k8kCbUbOet tuh/fDCQFtRKGhho2OVhSbM= Received: (qmail 9078 invoked by alias); 12 Jan 2017 14:30:35 -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 8942 invoked by uid 89); 12 Jan 2017 14:30:28 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-5.1 required=5.0 tests=BAYES_00, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=wwww3org, UD:www.w3.org, xmlns, www.w3.org 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 ESMTP; Thu, 12 Jan 2017 14:29:56 +0000 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C6A864F639; Thu, 12 Jan 2017 14:29:55 +0000 (UTC) Received: from localhost (ovpn-116-26.ams2.redhat.com [10.36.116.26]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v0CETsnU005299; Thu, 12 Jan 2017 09:29:55 -0500 Date: Thu, 12 Jan 2017 14:29:53 +0000 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH] PR66284 remove std::function special case for reference_wrapper Message-ID: <20170112142953.GW13348@redhat.com> MIME-Version: 1.0 Content-Disposition: inline X-Clacks-Overhead: GNU Terry Pratchett User-Agent: Mutt/1.7.1 (2016-10-04) As the PR says, we follow the Boost.Function semantics w.r.t. construction of std::function from a std::reference_wrapper, but other std::lib implementations do something different. I reported a defect (LWG 2781) and the consensus is to clarify the standard to bless the other implementations. This modifies our std::function to have the correct semantics. Previously passing a std::reference_wrapper to a std::function constructor would unwrap it and store an F*, but target_type() would return typeid(F). With the change it stores std::reference_wrapper and target_type() returns typeid(std::reference_wrapper). This is more straightforward, as there's no cleverness being done behind the scenes. The previous semantics required a special case in the non-const overload of std::function::target() to ensure it couldn't be used to drop const-qualification when the std::function was constructed from a std::reference_wrapper. Now that there's no unwrapping of reference_wrappers that isn't needed, and the non-const overload of target() can simply call the const overload and then const_cast the result. These are user-visible changes, but I doubt much code will be affected. PR libstdc++/66284 * doc/xml/manual/intro.xml: Document LWG 2781 change. * doc/html/*: Regenerate. * include/std/functional (_Function_base::_Ref_manager): Remove. (_Function_handler): Remove partial specializations for reference_wrapper. (function::target): Remove special case for const qualification. * testsuite/20_util/function/6.cc: Adjust tests for target type. * testsuite/20_util/function/7.cc: Likewise. * testsuite/20_util/function/8.cc: Likewise. Tested powerpc64le-linux, committed to trunk. commit 0966b4fdc1d5747f0cd63305546094f80c327d2b Author: Jonathan Wakely Date: Thu Jan 12 14:22:13 2017 +0000 PR66284 remove std::function special case for reference_wrapper PR libstdc++/66284 * doc/xml/manual/intro.xml: Document LWG 2781 change. * doc/html/*: Regenerate. * include/std/functional (_Function_base::_Ref_manager): Remove. (_Function_handler): Remove partial specializations for reference_wrapper. (function::target): Remove special case for const qualification. * testsuite/20_util/function/6.cc: Adjust tests for target type. * testsuite/20_util/function/7.cc: Likewise. * testsuite/20_util/function/8.cc: Likewise. diff --git a/libstdc++-v3/doc/xml/manual/intro.xml b/libstdc++-v3/doc/xml/manual/intro.xml index d23008a..db6e09a 100644 --- a/libstdc++-v3/doc/xml/manual/intro.xml +++ b/libstdc++-v3/doc/xml/manual/intro.xml @@ -1116,6 +1116,15 @@ requirements of the license of GCC. only use it if valid. + 2781: + Contradictory requirements for std::function + and std::reference_wrapper + + + Remove special handling for reference_wrapper + arguments and store them directly as the target object. + + diff --git a/libstdc++-v3/include/bits/std_function.h b/libstdc++-v3/include/bits/std_function.h index f7bb22a..7d77e21 100644 --- a/libstdc++-v3/include/bits/std_function.h +++ b/libstdc++-v3/include/bits/std_function.h @@ -268,41 +268,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { __functor._M_access<_Functor*>() = new _Functor(std::move(__f)); } }; - template - class _Ref_manager : public _Base_manager<_Functor*> - { - typedef _Function_base::_Base_manager<_Functor*> _Base; - - public: - static bool - _M_manager(_Any_data& __dest, const _Any_data& __source, - _Manager_operation __op) - { - switch (__op) - { -#if __cpp_rtti - case __get_type_info: - __dest._M_access() = &typeid(_Functor); - break; -#endif - case __get_functor_ptr: - __dest._M_access<_Functor*>() = *_Base::_M_get_pointer(__source); - return is_const<_Functor>::value; - break; - - default: - _Base::_M_manager(__dest, __source, __op); - } - return false; - } - - static void - _M_init_functor(_Any_data& __functor, reference_wrapper<_Functor> __f) - { - _Base::_M_init_functor(__functor, std::__addressof(__f.get())); - } - }; - _Function_base() : _M_manager(nullptr) { } ~_Function_base() @@ -311,7 +276,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_manager(_M_functor, _M_functor, __destroy_functor); } - bool _M_empty() const { return !_M_manager; } typedef bool (*_Manager_type)(_Any_data&, const _Any_data&, @@ -354,36 +318,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } }; - template - class _Function_handler<_Res(_ArgTypes...), reference_wrapper<_Functor> > - : public _Function_base::_Ref_manager<_Functor> - { - typedef _Function_base::_Ref_manager<_Functor> _Base; - - public: - static _Res - _M_invoke(const _Any_data& __functor, _ArgTypes&&... __args) - { - return std::__invoke(**_Base::_M_get_pointer(__functor), - std::forward<_ArgTypes>(__args)...); - } - }; - - template - class _Function_handler > - : public _Function_base::_Ref_manager<_Functor> - { - typedef _Function_base::_Ref_manager<_Functor> _Base; - - public: - static void - _M_invoke(const _Any_data& __functor, _ArgTypes&&... __args) - { - std::__invoke(**_Base::_M_get_pointer(__functor), - std::forward<_ArgTypes>(__args)...); - } - }; - template class _Function_handler<_Res(_ArgTypes...), _Member _Class::*> @@ -677,15 +611,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @brief Access the stored target function object. * * @return Returns a pointer to the stored target function object, - * if @c typeid(Functor).equals(target_type()); otherwise, a NULL + * if @c typeid(_Functor).equals(target_type()); otherwise, a NULL * pointer. * - * This function will not throw an %exception. + * This function does not throw exceptions. + * + * @{ */ template _Functor* target() noexcept; - /// @overload template const _Functor* target() const noexcept; + // @} #endif private: @@ -755,17 +691,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION function<_Res(_ArgTypes...)>:: target() noexcept { - if (typeid(_Functor) == target_type() && _M_manager) - { - _Any_data __ptr; - if (_M_manager(__ptr, _M_functor, __get_functor_ptr) - && !is_const<_Functor>::value) - return 0; - else - return __ptr._M_access<_Functor*>(); - } - else - return 0; + const function* __const_this = this; + const _Functor* __func = __const_this->template target<_Functor>(); + return const_cast<_Functor*>(__func); } template @@ -781,7 +709,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __ptr._M_access(); } else - return 0; + return nullptr; } #endif diff --git a/libstdc++-v3/testsuite/20_util/function/6.cc b/libstdc++-v3/testsuite/20_util/function/6.cc index 94c1234..c224ec5 100644 --- a/libstdc++-v3/testsuite/20_util/function/6.cc +++ b/libstdc++-v3/testsuite/20_util/function/6.cc @@ -22,7 +22,20 @@ #include #include -using namespace __gnu_test; +template + const T& + as_const(T& t) + { return t; } + +// Check that f's target is a reference_wrapper bound to obj. +template + bool + wraps(Function& f, T& obj) + { + using ref_wrapper_type = std::reference_wrapper; + auto* p = f.template target(); + return std::addressof(p->get()) == std::addressof(obj); + } struct secret {}; @@ -52,25 +65,24 @@ void test06() function f(ref(x)); VERIFY( f ); VERIFY( f() == 17 ); - VERIFY( f.target_type() == typeid(noncopyable_function_object_type) ); - VERIFY( f.target() == &x ); + VERIFY( f.target_type() == typeid(std::ref(x)) ); // LWG 2781 + VERIFY( wraps(f, x) ); function g = f; VERIFY( g ); VERIFY( g() == 17 ); - VERIFY( g.target_type() == typeid(noncopyable_function_object_type) ); - VERIFY( g.target() == &x ); + VERIFY( g.target_type() == f.target_type() ); + VERIFY( wraps(g, x) ); function h = cref(x); VERIFY( h ); VERIFY( h() == 42 ); - VERIFY( h.target_type() == typeid(noncopyable_function_object_type) ); - VERIFY( h.target() == &x ); - VERIFY( h.target() == &x ); + VERIFY( h.target_type() == typeid(std::cref(x)) ); + VERIFY( wraps(h, as_const(x)) ); const function& hc = h; - VERIFY( h.target() == 0 ); - VERIFY( hc.target() == &x ); + VERIFY( hc.target_type() == h.target_type() ); + VERIFY( wraps(hc, as_const(x)) ); } int main() diff --git a/libstdc++-v3/testsuite/20_util/function/7.cc b/libstdc++-v3/testsuite/20_util/function/7.cc index 28337f4..b10ecb8 100644 --- a/libstdc++-v3/testsuite/20_util/function/7.cc +++ b/libstdc++-v3/testsuite/20_util/function/7.cc @@ -23,7 +23,20 @@ #include #include -using namespace __gnu_test; +template + const T& + as_const(T& t) + { return t; } + +// Check that f's target is a reference_wrapper bound to obj. +template + bool + wraps(Function& f, T& obj) + { + using ref_wrapper_type = std::reference_wrapper; + auto* p = f.template target(); + return std::addressof(p->get()) == std::addressof(obj); + } // Put reference_wrappers to function pointers into function<> wrappers void test07() @@ -31,8 +44,9 @@ void test07() using std::function; using std::ref; using std::cref; + using std::reference_wrapper; - int (*fptr)(float) = truncate_float; + int (*fptr)(float) = __gnu_test::truncate_float; function f1(ref(fptr)); VERIFY( f1 ); @@ -47,11 +61,11 @@ void test07() // target_type and target() functions const function& f1c = f1; - VERIFY( typeid(int(*)(float)) == f1.target_type() ); - VERIFY( f1.target() != 0 ); - VERIFY( f1.target() == &fptr ); - VERIFY( f1c.target() != 0 ); - VERIFY( f1c.target() == &fptr ); + using ref_wrapper_type = reference_wrapper; + VERIFY( typeid(ref_wrapper_type) == f1.target_type() ); + VERIFY( f1.target() != nullptr ); + VERIFY( wraps(f1, fptr) ); + VERIFY( wraps(f1c, fptr) ); function f2(cref(fptr)); VERIFY( f2 ); @@ -66,11 +80,11 @@ void test07() // target_type and target() functions const function& f2c = f2; - VERIFY( typeid(int(*)(float)) == f2.target_type() ); - VERIFY( f2.target() == 0 ); - VERIFY( f2.target() == &fptr ); - VERIFY( f2c.target() != 0 ); - VERIFY( f2c.target() == &fptr ); + using cref_wrapper_type = reference_wrapper; + VERIFY( typeid(cref_wrapper_type) == f2.target_type() ); + VERIFY( wraps(f2, as_const(fptr)) ); + VERIFY( f2c.target_type() == f2.target_type() ); + VERIFY( wraps(f2c, as_const(fptr)) ); } int main() diff --git a/libstdc++-v3/testsuite/20_util/function/8.cc b/libstdc++-v3/testsuite/20_util/function/8.cc index 3583994..e641057 100644 --- a/libstdc++-v3/testsuite/20_util/function/8.cc +++ b/libstdc++-v3/testsuite/20_util/function/8.cc @@ -23,7 +23,20 @@ #include #include -using namespace __gnu_test; +template + const T& + as_const(T& t) + { return t; } + +// Check that f's target is a reference_wrapper bound to obj. +template + bool + wraps(Function& f, T& obj) + { + using ref_wrapper_type = std::reference_wrapper; + auto* p = f.template target(); + return std::addressof(p->get()) == std::addressof(obj); + } // Put reference_wrappers to member pointers void test08() @@ -31,6 +44,8 @@ void test08() using std::function; using std::ref; using std::cref; + using std::reference_wrapper; + using __gnu_test::X; int X::* X_bar = &X::bar; int (X::* X_foo)() = &X::foo; @@ -44,99 +59,92 @@ void test08() function frm(ref(X_bar)); VERIFY( frm ); VERIFY( frm(x) == 17 ); - VERIFY( typeid(int X::*) == frm.target_type() ); - VERIFY( frm.target() == &X_bar ); + VERIFY( typeid(ref(X_bar)) == frm.target_type() ); + VERIFY( wraps(frm, X_bar) ); function fr(ref(X_foo)); VERIFY( fr ); VERIFY( fr(x) == 1 ); - VERIFY( typeid(int (X::*)()) == fr.target_type() ); - VERIFY( fr.target() == &X_foo ); + VERIFY( typeid(ref(X_foo)) == fr.target_type() ); + VERIFY( wraps(fr, X_foo) ); function frc(ref(X_foo_c)); VERIFY( frc ); VERIFY( frc(x) == 2 ); - VERIFY( typeid(int (X::*)() const) == frc.target_type() ); - VERIFY( frc.target() == &X_foo_c ); + VERIFY( typeid(ref(X_foo_c)) == frc.target_type() ); + VERIFY( wraps(frc, X_foo_c) ); function frv(ref(X_foo_v)); VERIFY( frv ); VERIFY( frv(x) == 3 ); - VERIFY( typeid(int (X::*)() volatile) == frv.target_type() ); - VERIFY( *frv.target() == X_foo_v ); - VERIFY( frv.target() == 0 ); + VERIFY( typeid(ref(X_foo_v)) == frv.target_type() ); + VERIFY( wraps(frv, X_foo_v) ); function frcv(ref(X_foo_cv)); VERIFY( frcv ); VERIFY( frcv(x) == 4 ); - VERIFY( typeid(int (X::*)() const volatile) == frcv.target_type() ); - VERIFY( *frcv.target() == X_foo_cv ); - VERIFY( frcv.target() == 0 ); + VERIFY( typeid(ref(X_foo_cv)) == frcv.target_type() ); + VERIFY( wraps(frcv, X_foo_cv) ); function grm(ref(X_bar)); VERIFY( grm ); VERIFY( grm(&x) == 17 ); - VERIFY( typeid(int X::*) == grm.target_type() ); - VERIFY( *grm.target() == X_bar ); + VERIFY( typeid(ref(X_bar)) == grm.target_type() ); + VERIFY( wraps(grm, X_bar) ); function gr(ref(X_foo)); VERIFY( gr ); VERIFY( gr(&x) == 1 ); - VERIFY( typeid(int (X::*)()) == gr.target_type() ); - VERIFY( *gr.target() == X_foo ); + VERIFY( typeid(ref(X_foo)) == gr.target_type() ); + VERIFY( wraps(gr, X_foo) ); function grc(ref(X_foo_c)); VERIFY( grc ); VERIFY( grc(&x) == 2 ); - VERIFY( typeid(int (X::*)() const) == grc.target_type() ); - VERIFY( *grc.target() == X_foo_c ); + VERIFY( typeid(ref(X_foo_c)) == grc.target_type() ); + VERIFY( wraps(grc, X_foo_c) ); function grv(ref(X_foo_v)); VERIFY( grv ); VERIFY( grv(&x) == 3 ); - VERIFY( typeid(int (X::*)() volatile) == grv.target_type() ); - VERIFY( *grv.target() == X_foo_v ); - VERIFY( grv.target() == 0 ); + VERIFY( typeid(ref(X_foo_v)) == grv.target_type() ); + VERIFY( wraps(grv, X_foo_v) ); function grcv(ref(X_foo_cv)); VERIFY( grcv ); VERIFY( grcv(&x) == 4 ); - VERIFY( typeid(int (X::*)() const volatile) == grcv.target_type() ); - VERIFY( *grcv.target() == X_foo_cv ); - VERIFY( grcv.target() == 0 ); + VERIFY( typeid(ref(X_foo_cv)) == grcv.target_type() ); + VERIFY( wraps(grcv, X_foo_cv) ); function hrm(cref(X_bar)); VERIFY( hrm ); VERIFY( hrm(x) == 17 ); - VERIFY( typeid(int X::*) == hrm.target_type() ); - VERIFY( hrm.target() == 0 ); - VERIFY( hrm.target() == &X_bar ); + VERIFY( typeid(cref(X_bar)) == hrm.target_type() ); + VERIFY( wraps(hrm, as_const(X_bar)) ); function hr(cref(X_foo)); VERIFY( hr ); VERIFY( hr(x) == 1 ); - VERIFY( typeid(int (X::*)()) == hr.target_type() ); - VERIFY( hr.target() == &X_foo ); + VERIFY( typeid(cref(X_foo)) == hr.target_type() ); + VERIFY( wraps(hr, as_const(X_foo)) ); function hrc(cref(X_foo_c)); VERIFY( hrc ); VERIFY( hrc(x) == 2 ); - VERIFY( typeid(int (X::*)() const) == hrc.target_type() ); - VERIFY( hrc.target() == &X_foo_c ); + VERIFY( typeid(cref(X_foo_c)) == hrc.target_type() ); + VERIFY( wraps(hrc, as_const(X_foo_c)) ); function hrv(cref(X_foo_v)); VERIFY( hrv ); VERIFY( hrv(x) == 3 ); - VERIFY( typeid(int (X::*)() volatile) == hrv.target_type() ); - VERIFY( hrv.target() == &X_foo_v ); - VERIFY( hrv.target() == 0 ); + VERIFY( typeid(cref(X_foo_v)) == hrv.target_type() ); + VERIFY( wraps(hrv, as_const(X_foo_v)) ); function hrcv(cref(X_foo_cv)); VERIFY( hrcv ); VERIFY( hrcv(x) == 4 ); - VERIFY( typeid(int (X::*)() const volatile) == hrcv.target_type() ); - VERIFY( hrcv.target() == &X_foo_cv ); - VERIFY( hrcv.target() == 0 ); + VERIFY( typeid(cref(X_foo_cv)) == hrcv.target_type() ); + VERIFY( wraps(hrcv, as_const(X_foo_cv)) ); } int main()