From: Jonathan Wakely <jwakely@redhat.com>
To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org
Subject: [committed] libstdc++: Implement P1328 "Making std::type_info::operator== constexpr"
Date: Wed, 5 Jan 2022 15:30:48 +0000 [thread overview]
Message-ID: <20220105153048.1775975-1-jwakely@redhat.com> (raw)
Tested powerpc64le-linux, pushed to trunk.
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.
---
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 ++++++++++++-------
.../18_support/type_info/constexpr.cc | 48 ++++++++++
6 files changed, 131 insertions(+), 34 deletions(-)
create mode 100644 libstdc++-v3/testsuite/18_support/type_info/constexpr.cc
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<char>::_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 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,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 <typeinfo>
+
+#ifndef __cpp_lib_constexpr_typeinfo
+# error "Feature-test macro for constexpr typeinfo missing in <typeinfo>"
+#elif __cpp_lib_constexpr_typeinfo != 202106L
+# error "Feature-test macro for constexpr typeinfo has wrong value in <typeinfo>"
+#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() );
--
2.31.1
reply other threads:[~2022-01-05 15:30 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220105153048.1775975-1-jwakely@redhat.com \
--to=jwakely@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=libstdc++@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).