From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 48601 invoked by alias); 15 Aug 2019 16:07:11 -0000 Mailing-List: contact libstdc++-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libstdc++-owner@gcc.gnu.org Received: (qmail 48588 invoked by uid 89); 15 Aug 2019 16:07:11 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-16.3 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,SPF_HELO_PASS autolearn=ham version=3.3.1 spammy=201703l, 201703L 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, 15 Aug 2019 16:07:08 +0000 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9E9F8796ED; Thu, 15 Aug 2019 16:07:07 +0000 (UTC) Received: from localhost (unknown [10.33.36.6]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2F978600CD; Thu, 15 Aug 2019 16:07:06 +0000 (UTC) Date: Thu, 15 Aug 2019 16:07:00 -0000 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: Re: [PATCH] PR libstdc++/91456 make INVOKE work with uncopyable prvalues Message-ID: <20190815160706.GN9487@redhat.com> References: <20190815160428.GA5540@redhat.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="Do4IU1xF/9sod/r6" Content-Disposition: inline In-Reply-To: <20190815160428.GA5540@redhat.com> X-Clacks-Overhead: GNU Terry Pratchett User-Agent: Mutt/1.12.0 (2019-05-25) X-IsSubscribed: yes X-SW-Source: 2019-08/txt/msg00035.txt.bz2 --Do4IU1xF/9sod/r6 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Disposition: inline Content-length: 1624 On 15/08/19 17:04 +0100, Jonathan Wakely wrote: >In C++17 a function can return a prvalue of a type that cannot be moved >or copied. The current implementation of std::is_invocable_r uses >std::is_convertible to test the conversion to R required by INVOKE. >That fails for non-copyable prvalues, because std::is_convertible is >defined in terms of std::declval which uses std::add_rvalue_reference. >In C++17 conversion from R to R involves no copies and so is not the >same as conversion from R&& to R. > >This commit changes std::is_invocable_r to check the conversion without >using std::is_convertible. > >std::function also contains a similar check using std::is_convertible, >which can be fixed by simply reusing std::is_invocable_r (but because >std::is_invocable_r is not defined for C++11 it uses the underlying >std::__is_invocable_impl trait directly). > > PR libstdc++/91456 > * include/bits/std_function.h (__check_func_return_type): Remove. > (function::_Callable): Use std::__is_invocable_impl instead of > __check_func_return_type. > * include/std/type_traits (__is_invocable_impl): Add another defaulted > template parameter. Define a separate partial specialization for > INVOKE and INVOKE. For INVOKE replace is_convertible check > with a check that models delayed temporary materialization. > * testsuite/20_util/function/91456.cc: New test. > * testsuite/20_util/is_invocable/91456.cc: New test. With some minor changes to __is_convertible_helper we could make that usable by both std::is_convertible and __is_invokable_impl. I don't plan to commit this now but might do at a later date. --Do4IU1xF/9sod/r6 Content-Type: text/x-patch; charset=us-ascii Content-Disposition: attachment; filename="patch.txt" Content-length: 4166 diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index 44db2cade5d..4df3fee4c77 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -1491,20 +1491,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION bool = __or_, is_function<_To>, is_array<_To>>::value> struct __is_convertible_helper - { - typedef typename is_void<_To>::type type; - }; + : public is_void<_To>::type + { }; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wctor-dtor-privacy" template class __is_convertible_helper<_From, _To, false> { + // Unlike declval, this doesn't add_rvalue_reference. + template + static _From1 __declval(); + template static void __test_aux(_To1) noexcept; template(std::declval<_From1>()))> + typename = decltype(__test_aux<_To1>(__declval<_From1>()))> static true_type __test(int); @@ -1513,14 +1516,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __test(...); public: - typedef decltype(__test<_From, _To>(0)) type; + using type = decltype(__test<_From, _To>(0)); }; #pragma GCC diagnostic pop + template struct add_rvalue_reference; + /// is_convertible template struct is_convertible - : public __is_convertible_helper<_From, _To>::type + : public __is_convertible_helper::type, + _To>::type { }; template class __is_nt_convertible_helper<_From, _To, false> { + // Unlike declval, this doesn't add_rvalue_reference. + template + static _From1 __declval(); + template static void __test_aux(_To1) noexcept; template static - __bool_constant(std::declval<_From1>()))> + __bool_constant(__declval<_From1>()))> __test(int); template @@ -1555,14 +1565,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // is_nothrow_convertible for C++11 template struct __is_nothrow_convertible - : public __is_nt_convertible_helper<_From, _To>::type + : __is_nt_convertible_helper::type, + _To>::type { }; #if __cplusplus > 201703L /// is_nothrow_convertible template struct is_nothrow_convertible - : public __is_nt_convertible_helper<_From, _To>::type + : __is_nt_convertible_helper::type, + _To>::type { }; /// is_nothrow_convertible_v @@ -2896,35 +2908,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : true_type { }; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" // Used for INVOKE expressions to check the implicit conversion to R. template struct __is_invocable_impl<_Result, _Ret, /* is_void<_Ret> = */ false, __void_t> - { - private: - // The type of the INVOKE expression. - // Unlike declval, this doesn't add_rvalue_reference. - static typename _Result::type _S_get(); - - template - static void _S_conv(_Tp); - - // This overload is viable if INVOKE(f, args...) can convert to _Tp. - template(_S_get()))> - static true_type - _S_test(int); - - template - static false_type - _S_test(...); - - public: - using type = decltype(_S_test<_Ret>(1)); - }; -#pragma GCC diagnostic pop + : __is_convertible_helper + { }; template struct __is_invocable --Do4IU1xF/9sod/r6--