From patchwork Sun Nov 14 23:11:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 47640 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C402E3858006 for ; Sun, 14 Nov 2021 23:11:34 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C402E3858006 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1636931494; bh=WVtwfpYZdQZHjOqxuaupUss4W6Zwbrjv/YZs79dmLNc=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=LK7QaptcRGD2/yRAioO0pG1wy+zMQQvlIeM9V6PAQwHCT1V7bNcacf17QRIkNTRhM d53ftL4PSkT/p3HdNEW61xzXHR3eNS9Xhujk9XqgRtz/oS+Mmdn54hDOYOHh9o+V7S Tx/ipxPoUH+7iPy3zL/N1aciXfmk5DxstzuYCI3k= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 3EB7F3858D39 for ; Sun, 14 Nov 2021 23:11:04 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 3EB7F3858D39 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-460-Xha3ynwdN6KBwA9-WurzAA-1; Sun, 14 Nov 2021 18:11:02 -0500 X-MC-Unique: Xha3ynwdN6KBwA9-WurzAA-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 859941B2C980; Sun, 14 Nov 2021 23:11:01 +0000 (UTC) Received: from localhost (unknown [10.33.36.17]) by smtp.corp.redhat.com (Postfix) with ESMTP id 214CF5DEFB; Sun, 14 Nov 2021 23:11:00 +0000 (UTC) To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH] libstdc++: Implement P1328 "Making std::type_info::operator== constexpr" Date: Sun, 14 Nov 2021 23:11:00 +0000 Message-Id: <20211114231100.3561315-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-14.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Jonathan Wakely via Gcc-patches From: Jonathan Wakely Reply-To: Jonathan Wakely Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" Not committed yet ... This feature is present in the C++23 draft. The ARM EABI requires that the type_info::operator== function can be defined out-of-line (and suggests that should be the default). With this patch, we fail to conform to that in C++23 mode. I think we might want to move the logic from operator== into a separate std::type_info::__equal function, which can be non-inline even if the actual type_info::operator== function is constexpr (and so implicitly inline). That isn't done by this patch, but probably should be. libstdc++-v3/ChangeLog: * include/bits/c++config (_GLIBCXX23_CONSTEXPR): Define. * include/std/version (__cpp_lib_constexpr_typeinfo): Define. * libsupc++/tinfo.cc: Add #error to ensure non-inline definition is emitted. * libsupc++/typeinfo (type_info::name()): Avoid branching. (type_info::before): Combine different implementations into one. (type_info::operator==): Likewise. --- libstdc++-v3/include/bits/c++config | 10 +++- libstdc++-v3/include/std/version | 1 + libstdc++-v3/libsupc++/tinfo.cc | 4 ++ libstdc++-v3/libsupc++/typeinfo | 90 ++++++++++++++++++----------- 4 files changed, 70 insertions(+), 35 deletions(-) diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config index 4b7fa659300..4ae635c8a56 100644 --- a/libstdc++-v3/include/bits/c++config +++ b/libstdc++-v3/include/bits/c++config @@ -175,13 +175,21 @@ #endif #ifndef _GLIBCXX20_CONSTEXPR -# if __cplusplus > 201703L +# if __cplusplus >= 202002L # define _GLIBCXX20_CONSTEXPR constexpr # else # define _GLIBCXX20_CONSTEXPR # endif #endif +#ifndef _GLIBCXX23_CONSTEXPR +# if __cplusplus >= 202100L +# define _GLIBCXX23_CONSTEXPR constexpr +# else +# define _GLIBCXX23_CONSTEXPR +# endif +#endif + #ifndef _GLIBCXX17_INLINE # if __cplusplus >= 201703L # define _GLIBCXX17_INLINE inline diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version index 0930de82efa..e8d696fa72f 100644 --- a/libstdc++-v3/include/std/version +++ b/libstdc++-v3/include/std/version @@ -290,6 +290,7 @@ #if __cplusplus > 202002L // c++2b #define __cpp_lib_adaptor_iterator_pair_constructor 202106L +#define __cpp_lib_constexpr_typeinfo 202106L #define __cpp_lib_invoke_r 202106L #define __cpp_lib_is_scoped_enum 202011L #if __cpp_lib_concepts diff --git a/libstdc++-v3/libsupc++/tinfo.cc b/libstdc++-v3/libsupc++/tinfo.cc index a620e23e91c..5356fbbedd3 100644 --- a/libstdc++-v3/libsupc++/tinfo.cc +++ b/libstdc++-v3/libsupc++/tinfo.cc @@ -32,6 +32,10 @@ std::type_info:: #if !__GXX_TYPEINFO_EQUALITY_INLINE +#if __cplusplus > 202002L +# error "this file must be compiled with C++20 or older to define operator==" +#endif + // We can't rely on common symbols being shared between shared objects. bool std::type_info:: operator== (const std::type_info& arg) const _GLIBCXX_NOEXCEPT diff --git a/libstdc++-v3/libsupc++/typeinfo b/libstdc++-v3/libsupc++/typeinfo index 975321f2017..06769e0c243 100644 --- a/libstdc++-v3/libsupc++/typeinfo +++ b/libstdc++-v3/libsupc++/typeinfo @@ -38,6 +38,10 @@ #pragma GCC visibility push(default) +#if __cplusplus >= 202101L +# define __cpp_lib_constexpr_typeinfo 202106L +#endif + extern "C++" { namespace __cxxabiv1 @@ -97,42 +101,14 @@ namespace std /** Returns an @e implementation-defined byte string; this is not * portable between compilers! */ const char* name() const _GLIBCXX_NOEXCEPT - { return __name[0] == '*' ? __name + 1 : __name; } + { return __name + int(__name[0] == '*'); } -#if !__GXX_TYPEINFO_EQUALITY_INLINE - // In old abi, or when weak symbols are not supported, there can - // be multiple instances of a type_info object for one - // type. Uniqueness must use the _name value, not object address. - bool before(const type_info& __arg) const _GLIBCXX_NOEXCEPT; - bool operator==(const type_info& __arg) const _GLIBCXX_NOEXCEPT; -#else - #if !__GXX_MERGED_TYPEINFO_NAMES - /** Returns true if @c *this precedes @c __arg in the implementation's + /** Returns true if `*this` precedes `__arg` in the implementation's * collation order. */ - // Even with the new abi, on systems that support dlopen - // we can run into cases where type_info names aren't merged, - // so we still need to do string comparison. - bool before(const type_info& __arg) const _GLIBCXX_NOEXCEPT - { return (__name[0] == '*' && __arg.__name[0] == '*') - ? __name < __arg.__name - : __builtin_strcmp (__name, __arg.__name) < 0; } + bool before(const type_info& __arg) const _GLIBCXX_NOEXCEPT; - bool operator==(const type_info& __arg) const _GLIBCXX_NOEXCEPT - { - return ((__name == __arg.__name) - || (__name[0] != '*' && - __builtin_strcmp (__name, __arg.__name) == 0)); - } - #else - // On some targets we can rely on type_info's NTBS being unique, - // and therefore address comparisons are sufficient. - bool before(const type_info& __arg) const _GLIBCXX_NOEXCEPT - { return __name < __arg.__name; } - - bool operator==(const type_info& __arg) const _GLIBCXX_NOEXCEPT - { return __name == __arg.__name; } - #endif -#endif + _GLIBCXX23_CONSTEXPR + bool operator==(const type_info& __arg) const _GLIBCXX_NOEXCEPT; #if __cpp_impl_three_way_comparison < 201907L bool operator!=(const type_info& __arg) const _GLIBCXX_NOEXCEPT @@ -176,11 +152,57 @@ namespace std explicit type_info(const char *__n): __name(__n) { } private: - /// Assigning type_info is not supported. + // type_info objects cannot be copied. +#if __cplusplus >= 201103L + type_info& operator=(const type_info&) = delete; + type_info(const type_info&) = delete; +#else type_info& operator=(const type_info&); type_info(const type_info&); +#endif }; +#if __GXX_TYPEINFO_EQUALITY_INLINE + inline bool + type_info::before(const type_info& __arg) const _GLIBCXX_NOEXCEPT + { +#if !__GXX_MERGED_TYPEINFO_NAMES + // Even with the new abi, on systems that support dlopen + // we can run into cases where type_info names aren't merged, + // so we still need to do string comparison. + if (__name[0] != '*' || __arg.__name[0] != '*') + return __builtin_strcmp (__name, __arg.__name) < 0; +#else + // On some targets we can rely on type_info's NTBS being unique, + // and therefore address comparisons are sufficient. +#endif + + // In old abi, or when weak symbols are not supported, there can + // be multiple instances of a type_info object for one + // type. Uniqueness must use the __name value, not object address. + return __name < __arg.__name; + } +#endif + +#if __GXX_TYPEINFO_EQUALITY_INLINE || __cplusplus > 202002L + _GLIBCXX23_CONSTEXPR inline bool + type_info::operator==(const type_info& __arg) const _GLIBCXX_NOEXCEPT + { + if (__name == __arg.__name) + return true; + +#if !__GXX_MERGED_TYPEINFO_NAMES +# if __has_builtin(__builtin_is_constant_evaluated) + if (!__builtin_is_constant_evaluated()) +# endif + return __name[0] != '*' && __builtin_strcmp (__name, __arg.name()) == 0; +#endif + + return false; + } +# endif + + /** * @brief Thrown during incorrect typecasting. * @ingroup exceptions