From patchwork Fri Aug 16 15:35:49 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 1148298 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-507138-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="CbvKU/6d"; dkim-atps=neutral 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 4696qT2hN9z9s00 for ; Sat, 17 Aug 2019 01:36:19 +1000 (AEST) 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=C9Mf0+AdfLX2BUBG0vFCe1D4b8gTbW+bzYyGHqhEl0Cii40j1NynZ 9xmSlAPNUwk7wiZP4xMDJhqWDZyRIFD514KVBP0sI2dzSmPc5AhGX8rw6Jp4t5ju 7KxuLOwbOj5zhkYM8zyQ0CafkR/xh0YKAYh31q93jSn4Da8cAGNxWI= 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=PfFBB53OVkKhz0YBgG2312lnc/U=; b=CbvKU/6dPF57AR9n3ZUU 1sMV1fNy3pKI/dKMnygXkxM5bu3u9gf6ygzjuEiHvB15P1H5e1ymCjXNEmQvzPq0 +8upALrtFBwu5ZtzEYQAjsd9CCsaU4LDMPa5QRKsyfasUeWLXFwRogApQ5Q1zxnr WIt3nNeWsYto7JPdBhXPPds= Received: (qmail 118475 invoked by alias); 16 Aug 2019 15:36:03 -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 118461 invoked by uid 89); 16 Aug 2019 15:36:03 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-15.3 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_HELO_PASS, UNSUBSCRIBE_BODY autolearn=ham version=3.3.1 spammy=sk:jwakely, sk:_GLIBCX, sk:_glibcx, jwakelyredhatcom 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; Fri, 16 Aug 2019 15:35:52 +0000 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 75F2D3084031; Fri, 16 Aug 2019 15:35:51 +0000 (UTC) Received: from localhost (unknown [10.33.36.6]) by smtp.corp.redhat.com (Postfix) with ESMTP id 80D2117AD8; Fri, 16 Aug 2019 15:35:50 +0000 (UTC) Date: Fri, 16 Aug 2019 16:35:49 +0100 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH] PR libstdc++/91371 make std::is_function handle other calling conventions Message-ID: <20190816153549.GA4140@redhat.com> MIME-Version: 1.0 Content-Disposition: inline X-Clacks-Overhead: GNU Terry Pratchett User-Agent: Mutt/1.12.0 (2019-05-25) The x86 attributes such as ms_abi, stdcall, fastcall etc. alter the function type, which means that functions with one of those attributes do not match any of the partial specializations of std::is_function. Rather than duplicating the list for every calling convention, this adds a fallback to the std::is_function primary template which identifies other function types. The fallback works by assuming that all function types fall into one of two categories: referenceable and abominable. The former can be detected by testing for function-to-pointer decay, and the latter are non-referenceable types that are not cv void. In order to detect referenceable types it's necessary to replace the current definition of __is_referenceable with one that doesn't depend on std::is_function, to avoid a cycle. The definition of std::decay can also be modified to only act on referenceable function types, because abominable function types do not decay. PR libstdc++/91371 * include/std/type_traits (__declval, declval, __void_t): Declare earlier in the file. (__is_referenceable): Rewrite to not depend on is_function. (__is_referenceable_function): New trait to identify non-abominable function types. (__is_qualified_function): New alias to identify abominable function types. (is_function): Make primary template use __is_referenceable_function and __is_qualified_function to detect function types not covered by the partial specializations. (__decay_selector): Use __is_referenceable_function instead of is_function. (__decay_selector<_Up, false, true>): Do not use add_pointer. * testsuite/20_util/bind/91371.cc: New test. * testsuite/20_util/is_function/91371.cc: New test. * testsuite/20_util/is_function/value.cc: Check more pointer types. * testsuite/20_util/is_member_function_pointer/91371.cc: New test. Tested x86_64-linux. Not committed yet. I'd like to hear Daniel's thoughts on this approach, as he wrote the original __is_referenceable trait, and much of . This new __is_referenceable simply uses void_t to detect whether forming T& is valid. The detection for function-to-pointer decay works by checking whether static_cast(declval()) is well-formed. If T is not a class type (which could have a conversion operator) and is not nullptr or cv void*cv (which can convert to nullptr* and cv void*cv* repectively) then it must be a function. The detection for abominable function types assumes that all types are referenceable except functions with cv- or ref-qualifiers and cv void types. So if it's not referenceable and not void, it's an abominable function type. commit 2c8c1d0ef4b9ed6e80abf3694618c0e63859de78 Author: Jonathan Wakely Date: Fri Aug 16 15:03:54 2019 +0100 PR libstdc++/91371 make std::is_function handle other calling conventions The x86 attributes such as ms_abi, stdcall, fastcall etc. alter the function type, which means that functions with one of those attributes do not match any of the partial specializations of std::is_function. Rather than duplicating the list for every calling convention, add a fallback to the std::is_function primary template which identifies other function types. The fallback works by assuming that all function types fall into one of two categories: referenceable and abominable. The former can be detected by testing for function-to-pointer decay, and the latter are non-referenceable types that are not cv void. In order to detect referenceable types it's necessary to replace the current definition of __is_referenceable with one that doesn't depend on std::is_function, to avoid a cycle. The definition of std::decay can also be modified to only act on referenceable function types, because abominable function types do not decay. PR libstdc++/91371 * include/std/type_traits (__declval, declval, __void_t): Declare earlier in the file. (__is_referenceable): Rewrite to not depend on is_function. (__is_referenceable_function): New trait to identify non-abominable function types. (__is_qualified_function): New alias to identify abominable function types. (is_function): Make primary template use __is_referenceable_function and __is_qualified_function to detect function types not covered by the partial specializations. (__decay_selector): Use __is_referenceable_function instead of is_function. (__decay_selector<_Up, false, true>): Do not use add_pointer. * testsuite/20_util/bind/91371.cc: New test. * testsuite/20_util/is_function/91371.cc: New test. * testsuite/20_util/is_function/value.cc: Check more pointer types. * testsuite/20_util/is_member_function_pointer/91371.cc: New test. diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index 44db2cade5d..ca16cb7ccc1 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -480,10 +480,64 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : public integral_constant { }; + template + _Up + __declval(int); + + template + _Tp + __declval(long); + + /** + * @brief Utility to simplify expressions used in unevaluated operands + * @ingroup utilities + */ + template + auto declval() noexcept -> decltype(__declval<_Tp>(0)); + + // __void_t (std::void_t for C++11) + template using __void_t = void; + + template struct is_null_pointer; + + // Utility to detect referenceable types ([defns.referenceable]). + template + struct __is_referenceable + : false_type { }; + + template + struct __is_referenceable<_Tp, __void_t<_Tp&>> + : true_type { }; + + // A function type that does not have cv-qualifiers or a ref-qualifier. + template + struct __is_referenceable_function + : false_type { }; + + template + struct __is_referenceable_function<_Tp, false, + __void_t(std::declval<_Tp&>()))>> + : __not_<__or_, is_null_pointer<_Tp>>>::type { }; + + // A function type with cv-qualifiers and/or a ref-qualifier. + // This assumes that only types that are not referenceable are cv void types + // and qualified function types. + template + using __is_qualified_function + = __not_<__or_<__is_referenceable<_Tp>, is_void<_Tp>>>; + /// is_function - template + template struct is_function - : public false_type { }; + : __or_<__is_referenceable_function<_Tp>, + __is_qualified_function<_Tp>>::type + { }; + + // Define partial specializations for most function types. + // The primary template is used for function types with alternative + // calling conventions (such as x86 stdcall) and for non-function types. template struct is_function<_Res(_ArgTypes...) _GLIBCXX_NOEXCEPT_QUAL> @@ -705,24 +759,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif >; - - // Utility to detect referenceable types ([defns.referenceable]). - - template - struct __is_referenceable - : public __or_, is_reference<_Tp>>::type - { }; - - template - struct __is_referenceable<_Res(_Args...) _GLIBCXX_NOEXCEPT_QUAL> - : public true_type - { }; - - template - struct __is_referenceable<_Res(_Args......) _GLIBCXX_NOEXCEPT_QUAL> - : public true_type - { }; - // Type properties. /// is_const @@ -841,22 +877,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Destructible and constructible type properties. - /** - * @brief Utility to simplify expressions used in unevaluated operands - * @ingroup utilities - */ - - template - _Up - __declval(int); - - template - _Tp - __declval(long); - - template - auto declval() noexcept -> decltype(__declval<_Tp>(0)); - template struct extent; @@ -2186,7 +2206,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // in make_pair, make_tuple, etc. template::value, - bool _IsFunction = is_function<_Up>::value> + bool _IsFunction = __is_referenceable_function<_Up>::value> struct __decay_selector; // NB: DR 705. @@ -2200,7 +2220,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __decay_selector<_Up, false, true> - { typedef typename add_pointer<_Up>::type __type; }; + { typedef _Up* __type; }; /// decay template @@ -2261,9 +2281,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct conditional { typedef _Iffalse type; }; - // __void_t (std::void_t for C++11) - template using __void_t = void; - /// common_type template struct common_type; diff --git a/libstdc++-v3/testsuite/20_util/bind/91371.cc b/libstdc++-v3/testsuite/20_util/bind/91371.cc new file mode 100644 index 00000000000..1c6f55e9ece --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/bind/91371.cc @@ -0,0 +1,37 @@ +// Copyright (C) 2019 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-do compile { target i?86-*-* x86_64-*-* } } +// { dg-require-effective-target c++11 } + +#include + +int bar(int) __attribute__((ms_abi)); +int baz(int) __attribute__((sysv_abi)); + +void +test01() +{ + // PR libstdc++/91371 + std::bind(bar, 5)(); + std::bind(baz, 5)(); + + static_assert(std::is_function::value, ""); + static_assert(std::is_function::value, ""); + static_assert(std::is_pointer>::value, ""); + static_assert(std::is_pointer>::value, ""); +} diff --git a/libstdc++-v3/testsuite/20_util/is_function/91371.cc b/libstdc++-v3/testsuite/20_util/is_function/91371.cc new file mode 100644 index 00000000000..c51d373027b --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/is_function/91371.cc @@ -0,0 +1,47 @@ +// Copyright (C) 2019 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-do compile { target i?86-*-* x86_64-*-* } } +// { dg-require-effective-target c++11 } + +#include + +using std::is_function; + +#ifdef __i386__ +static_assert(is_function::value, ""); +static_assert(is_function::value, ""); +static_assert(is_function::value, ""); +static_assert(is_function::value, ""); +static_assert(is_function::value, ""); +static_assert(is_function::value, ""); +#endif +static_assert(is_function::value, ""); +static_assert(is_function::value, ""); +static_assert(is_function::value, ""); +static_assert(is_function::value, ""); +static_assert(is_function::value, ""); +static_assert(is_function::value, ""); + +struct X { operator X*(); }; +static_assert(!is_function::value, ""); +static_assert(!is_function::value, ""); +static_assert(!is_function::value, ""); +union Y { operator Y*(); int i; long l;}; +static_assert(!is_function::value, ""); +static_assert(!is_function::value, ""); +static_assert(!is_function::value, ""); diff --git a/libstdc++-v3/testsuite/20_util/is_function/value.cc b/libstdc++-v3/testsuite/20_util/is_function/value.cc index 7b94b58b6cb..4a3bb7c5740 100644 --- a/libstdc++-v3/testsuite/20_util/is_function/value.cc +++ b/libstdc++-v3/testsuite/20_util/is_function/value.cc @@ -37,12 +37,18 @@ void test01() char (int, ClassType) const volatile &&>(true), ""); // Negative tests. + static_assert(test_category(false), ""); static_assert(test_category(false), ""); static_assert(test_category(false), ""); static_assert(test_category(false), ""); + static_assert(test_category(false), ""); + static_assert(test_category(false), ""); + static_assert(test_category(false), ""); + static_assert(test_category(false), ""); static_assert(test_category(false), ""); static_assert(test_category(false), ""); + static_assert(test_category(false), ""); // Sanity check. static_assert(test_category(false), ""); diff --git a/libstdc++-v3/testsuite/20_util/is_member_function_pointer/91371.cc b/libstdc++-v3/testsuite/20_util/is_member_function_pointer/91371.cc new file mode 100644 index 00000000000..25fecc11cd8 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/is_member_function_pointer/91371.cc @@ -0,0 +1,35 @@ +// Copyright (C) 2019 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-do compile { target i?86-*-* x86_64-*-* } } +// { dg-require-effective-target c++11 } + +#include + +struct Z +{ + void __attribute__((ms_abi)) f() const { } + void __attribute__((sysv_abi)) g() const { } +#ifdef __i386__ + void __attribute__((thiscall)) h() const { } +#endif +}; +static_assert( std::is_member_function_pointer::value, "" ); +static_assert( std::is_member_function_pointer::value, "" ); +#ifdef __i386__ +static_assert( std::is_member_function_pointer::value, "" ); +#endif