From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id B7AEC3858423; Wed, 5 Jan 2022 15:29:48 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B7AEC3858423 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r12-6266] libstdc++: Implement P1328 "Making std::type_info::operator== constexpr" X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/master X-Git-Oldrev: 096228d84e9238d97fe115623126373f5b67bdc1 X-Git-Newrev: 3633cc54284450433b81f0340483e15df1a49a3c Message-Id: <20220105152948.B7AEC3858423@sourceware.org> Date: Wed, 5 Jan 2022 15:29:48 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 05 Jan 2022 15:29:48 -0000 https://gcc.gnu.org/g:3633cc54284450433b81f0340483e15df1a49a3c commit r12-6266-g3633cc54284450433b81f0340483e15df1a49a3c Author: Jonathan Wakely Date: Wed Jan 5 14:25:37 2022 +0000 libstdc++: Implement P1328 "Making std::type_info::operator== constexpr" This feature is present in the C++23 draft. With Jakub's recent front-end changes we can implement constexpr equality by comparing the addresses of std::type_info objects. We do not need string comparisons, because for constant evaluation cases we know we aren't dealing with std::type_info objects defined in other translation units. The ARM EABI requires that the type_info::operator== function can be defined out-of-line (and suggests that should be the default), but to be a constexpr function it must be defined inline (at least for C++23 mode). To meet these conflicting requirements we make the inline version of operator== call a new __equal function when called at runtime. That is an alias for the non-inline definition of operator== defined in libsupc++. libstdc++-v3/ChangeLog: * config/abi/pre/gnu.ver (GLIBCXX_3.4.30): Export new symbol for ARM EABI. * 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. (type_info::__equal): Define alias symbol. * libsupc++/typeinfo (type_info::before): Combine different implementations into one. (type_info::operator==): Likewise. Use address equality for constant evaluation. Call __equal for targets that require the definition to be non-inline. * testsuite/18_support/type_info/constexpr.cc: New test. Diff: --- libstdc++-v3/config/abi/pre/gnu.ver | 3 + libstdc++-v3/include/bits/c++config | 10 ++- libstdc++-v3/include/std/version | 1 + libstdc++-v3/libsupc++/tinfo.cc | 7 ++ libstdc++-v3/libsupc++/typeinfo | 96 ++++++++++++++-------- .../testsuite/18_support/type_info/constexpr.cc | 48 +++++++++++ 6 files changed, 131 insertions(+), 34 deletions(-) diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver index c2f09a9290a..afd242b32aa 100644 --- a/libstdc++-v3/config/abi/pre/gnu.ver +++ b/libstdc++-v3/config/abi/pre/gnu.ver @@ -2424,6 +2424,9 @@ GLIBCXX_3.4.30 { # std::__timepunct::_M_am_pm_format(const char**) _ZNKSt11__timepunctI[cw]E15_M_am_pm_formatEPPK[cw]; + # Only defined #if ! __GXX_TYPEINFO_EQUALITY_INLINE + _ZNKSt9type_info7__equalERKS_; + } GLIBCXX_3.4.29; # Symbols in the support library (libsupc++) have their own tag. diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config index 3609793c0e6..c64b61b3c90 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 58760e69be8..f421056964e 100644 --- a/libstdc++-v3/include/std/version +++ b/libstdc++-v3/include/std/version @@ -295,6 +295,7 @@ // c++2b #define __cpp_lib_adaptor_iterator_pair_constructor 202106L #define __cpp_lib_byteswap 202110L +#define __cpp_lib_constexpr_typeinfo 202106L #define __cpp_lib_invoke_r 202106L #define __cpp_lib_ios_noreplace 202200L #define __cpp_lib_is_scoped_enum 202011L diff --git a/libstdc++-v3/libsupc++/tinfo.cc b/libstdc++-v3/libsupc++/tinfo.cc index f38472020d2..ef13dd33064 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 @@ -47,6 +51,9 @@ operator== (const std::type_info& arg) const _GLIBCXX_NOEXCEPT #endif } +bool +std::type_info::__equal (const std::type_info& arg) const _GLIBCXX_NOEXCEPT +__attribute__((alias("_ZNKSt9type_infoeqERKS_"))); #endif namespace std { diff --git a/libstdc++-v3/libsupc++/typeinfo b/libstdc++-v3/libsupc++/typeinfo index 91c30997403..3018a510fd5 100644 --- a/libstdc++-v3/libsupc++/typeinfo +++ b/libstdc++-v3/libsupc++/typeinfo @@ -38,6 +38,10 @@ #pragma GCC visibility push(default) +#if __cplusplus >= 202100L +# define __cpp_lib_constexpr_typeinfo 202106L +#endif + extern "C++" { namespace __cxxabiv1 @@ -99,40 +103,12 @@ namespace std const char* name() const _GLIBCXX_NOEXCEPT { return __name[0] == '*' ? __name + 1 : __name; } -#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 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 before(const type_info& __arg) const _GLIBCXX_NOEXCEPT; - 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,65 @@ 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 + bool __equal(const type_info&) const _GLIBCXX_NOEXCEPT; +#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 (std::__is_constant_evaluated()) + return this == &__arg; + + if (__name == __arg.__name) + return true; + +#if !__GXX_TYPEINFO_EQUALITY_INLINE + // ABI requires comparisons to be non-inline. + return __equal(__arg); +#elif !__GXX_MERGED_TYPEINFO_NAMES + // Need to do string comparison. + return __name[0] != '*' && __builtin_strcmp (__name, __arg.name()) == 0; +#else + return false; +#endif + } +# endif + + /** * @brief Thrown during incorrect typecasting. * @ingroup exceptions diff --git a/libstdc++-v3/testsuite/18_support/type_info/constexpr.cc b/libstdc++-v3/testsuite/18_support/type_info/constexpr.cc new file mode 100644 index 00000000000..07f4fb651f4 --- /dev/null +++ b/libstdc++-v3/testsuite/18_support/type_info/constexpr.cc @@ -0,0 +1,48 @@ +// { dg-options "-std=gnu++23 -frtti" } +// { dg-do compile { target c++23 } } + +#include + +#ifndef __cpp_lib_constexpr_typeinfo +# error "Feature-test macro for constexpr typeinfo missing in " +#elif __cpp_lib_constexpr_typeinfo != 202106L +# error "Feature-test macro for constexpr typeinfo has wrong value in " +#endif + +struct X { }; + +constexpr bool +test01() +{ + if (typeid(int) == typeid(long)) + return false; + + if (typeid(int) != typeid(int)) + return false; + + struct X { virtual ~X() { } }; + + if (typeid(X) != typeid(X)) + return false; + + if (typeid(X) == typeid(::X)) + return false; + + if (typeid(X) == typeid(int)) + return false; + + const auto& ti_x = typeid(X); + if (ti_x != ti_x) + return false; + + if (ti_x != typeid(X)) + return false; + + struct Y { }; + if (ti_x == typeid(Y)) + return false; + + return true; +} + +static_assert( test01() );