[libc++] Implement P1328R1 constexpr std::type_info::operator==
authorLouis Dionne <ldionne.2@gmail.com>
Tue, 7 Feb 2023 01:08:19 +0000 (17:08 -0800)
committerLouis Dionne <ldionne.2@gmail.com>
Wed, 8 Feb 2023 01:03:45 +0000 (17:03 -0800)
Differential Revision: https://reviews.llvm.org/D143447

libcxx/docs/FeatureTestMacroTable.rst
libcxx/docs/ReleaseNotes.rst
libcxx/docs/Status/Cxx2bPapers.csv
libcxx/include/typeinfo
libcxx/include/version
libcxx/test/std/language.support/support.limits/support.limits.general/typeinfo.version.compile.pass.cpp
libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
libcxx/test/std/language.support/support.rtti/type.info/type_info.equal.pass.cpp [new file with mode: 0644]
libcxx/utils/generate_feature_test_macro_components.py

index b46fc8c..df4dfc4 100644 (file)
@@ -316,7 +316,7 @@ Status
     ------------------------------------------------- -----------------
     ``__cpp_lib_constexpr_memory``                    ``202202L``
     ------------------------------------------------- -----------------
-    ``__cpp_lib_constexpr_typeinfo``                  *unimplemented*
+    ``__cpp_lib_constexpr_typeinfo``                  ``202106L``
     ------------------------------------------------- -----------------
     ``__cpp_lib_expected``                            ``202202L``
     ------------------------------------------------- -----------------
index 8a04afb..20b2b09 100644 (file)
@@ -38,6 +38,8 @@ What's New in Libc++ 17.0.0?
 Implemented Papers
 ------------------
 
+- P1328R1 - `constexpr type_info::operator==()`
+
 Improvements and New Features
 -----------------------------
 
index e3f39d4..626f6cd 100644 (file)
@@ -14,7 +14,7 @@
 "`P0401R6 <https://wg21.link/P0401R6>`__","LWG","Providing size feedback in the Allocator interface","June 2021","|Complete|","15.0"
 "`P0448R4 <https://wg21.link/P0448R4>`__","LWG","A strstream replacement using span<charT> as buffer","June 2021","",""
 "`P1132R8 <https://wg21.link/P1132R8>`__","LWG","out_ptr - a scalable output pointer abstraction","June 2021","",""
-"`P1328R1 <https://wg21.link/P1328R1>`__","LWG","Making std::type_info::operator== constexpr","June 2021","",""
+"`P1328R1 <https://wg21.link/P1328R1>`__","LWG","Making std::type_info::operator== constexpr","June 2021","|Complete|","17.0"
 "`P1425R4 <https://wg21.link/P1425R4>`__","LWG","Iterators pair constructors for stack and queue","June 2021","|Complete|","14.0","|ranges|"
 "`P1518R2 <https://wg21.link/P1518R2>`__","LWG","Stop overconstraining allocators in container deduction guides","June 2021","|Complete|","13.0"
 "`P1659R3 <https://wg21.link/P1659R3>`__","LWG","starts_with and ends_with","June 2021","","","|ranges|"
index 4431039..5627da1 100644 (file)
@@ -21,7 +21,7 @@ class type_info
 public:
     virtual ~type_info();
 
-    bool operator==(const type_info& rhs) const noexcept;
+    bool operator==(const type_info& rhs) const noexcept; // constexpr since C++23
     bool operator!=(const type_info& rhs) const noexcept; // removed in C++20
 
     bool before(const type_info& rhs) const noexcept;
@@ -59,6 +59,7 @@ public:
 #include <__assert> // all public C++ headers provide the assertion handler
 #include <__availability>
 #include <__config>
+#include <__type_traits/is_constant_evaluated.h>
 #include <cstddef>
 #include <cstdint>
 #include <cstdlib>
@@ -104,8 +105,13 @@ public:
 
     size_t hash_code() const _NOEXCEPT;
 
-    _LIBCPP_INLINE_VISIBILITY
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX23
     bool operator==(const type_info& __arg) const _NOEXCEPT {
+      // When evaluated in a constant expression, both type infos simply can't come
+      // from different translation units, so it is sufficient to compare their addresses.
+      if (__libcpp_is_constant_evaluated()) {
+        return this == &__arg;
+      }
       return __compare(__arg) == 0;
     }
 
@@ -330,9 +336,14 @@ public:
       return __impl::__hash(__type_name);
     }
 
-    _LIBCPP_INLINE_VISIBILITY
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX23
     bool operator==(const type_info& __arg) const _NOEXCEPT
     {
+      // When evaluated in a constant expression, both type infos simply can't come
+      // from different translation units, so it is sufficient to compare their addresses.
+      if (__libcpp_is_constant_evaluated()) {
+        return this == &__arg;
+      }
       return __impl::__eq(__type_name, __arg.__type_name);
     }
 
index 9705229..44a081a 100644 (file)
@@ -392,7 +392,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 // # define __cpp_lib_constexpr_cmath                      202202L
 # undef  __cpp_lib_constexpr_memory
 # define __cpp_lib_constexpr_memory                     202202L
-// # define __cpp_lib_constexpr_typeinfo                   202106L
+# define __cpp_lib_constexpr_typeinfo                   202106L
 # define __cpp_lib_expected                             202202L
 # define __cpp_lib_forward_like                         202207L
 // # define __cpp_lib_invoke_r                             202106L
index 75abf3e..3cb2502 100644 (file)
 
 #elif TEST_STD_VER > 20
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_constexpr_typeinfo
-#     error "__cpp_lib_constexpr_typeinfo should be defined in c++2b"
-#   endif
-#   if __cpp_lib_constexpr_typeinfo != 202106L
-#     error "__cpp_lib_constexpr_typeinfo should have the value 202106L in c++2b"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_constexpr_typeinfo
-#     error "__cpp_lib_constexpr_typeinfo should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_constexpr_typeinfo
+#   error "__cpp_lib_constexpr_typeinfo should be defined in c++2b"
+# endif
+# if __cpp_lib_constexpr_typeinfo != 202106L
+#   error "__cpp_lib_constexpr_typeinfo should have the value 202106L in c++2b"
 # endif
 
 #endif // TEST_STD_VER > 20
index 9c1816b..b02679d 100644 (file)
 #   error "__cpp_lib_constexpr_tuple should have the value 201811L in c++2b"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_constexpr_typeinfo
-#     error "__cpp_lib_constexpr_typeinfo should be defined in c++2b"
-#   endif
-#   if __cpp_lib_constexpr_typeinfo != 202106L
-#     error "__cpp_lib_constexpr_typeinfo should have the value 202106L in c++2b"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_constexpr_typeinfo
-#     error "__cpp_lib_constexpr_typeinfo should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_constexpr_typeinfo
+#   error "__cpp_lib_constexpr_typeinfo should be defined in c++2b"
+# endif
+# if __cpp_lib_constexpr_typeinfo != 202106L
+#   error "__cpp_lib_constexpr_typeinfo should have the value 202106L in c++2b"
 # endif
 
 # ifndef __cpp_lib_constexpr_utility
diff --git a/libcxx/test/std/language.support/support.rtti/type.info/type_info.equal.pass.cpp b/libcxx/test/std/language.support/support.rtti/type.info/type_info.equal.pass.cpp
new file mode 100644 (file)
index 0000000..3f5dd96
--- /dev/null
@@ -0,0 +1,79 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// class type_info
+//
+//  bool operator==(const type_info& rhs) const noexcept; // constexpr since C++23
+
+// UNSUPPORTED: no-rtti
+
+// When we build for Windows on top of the VC runtime, `typeinfo::operator==` may not
+// be `constexpr` (depending on the version of the VC runtime). So this test can fail.
+// UNSUPPORTED: target={{.+}}-windows-msvc && !libcpp-no-vcruntime
+
+#include <typeinfo>
+#include <cassert>
+
+#include "test_macros.h"
+
+struct Base {
+  virtual void func() {}
+};
+struct Derived : Base {
+  virtual void func() {}
+};
+
+TEST_CONSTEXPR_CXX23 bool test() {
+  // Test when storing typeid() in a const ref
+  {
+    std::type_info const& t1 = typeid(int);
+    std::type_info const& t2 = typeid(long);
+    assert(t1 == t1);
+    assert(t2 == t2);
+    assert(t1 != t2);
+  }
+
+  // Test when using `typeid()` directly
+  {
+    struct Foo { };
+    struct Bar { };
+    assert(typeid(Foo) == typeid(Foo));
+    assert(typeid(Foo) != typeid(Bar));
+  }
+
+  // Test when using typeid(object) instead of typeid(type)
+  {
+    int x = 0, y = 0;
+    long z = 0;
+    assert(typeid(x) == typeid(y));
+    assert(typeid(x) != typeid(z));
+  }
+
+  // Check with derived/base types
+  {
+    Derived derived;
+    Base const& as_base = derived;
+    assert(typeid(as_base) == typeid(Derived));
+  }
+
+  // Check noexcept-ness
+  {
+    std::type_info const& t1 = typeid(int); (void)t1;
+    std::type_info const& t2 = typeid(long); (void)t2;
+    ASSERT_NOEXCEPT(t1 == t2);
+  }
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 23
+  static_assert(test());
+#endif
+  return 0;
+}
index 69cb942..4cf52fb 100755 (executable)
@@ -267,7 +267,6 @@ feature_test_macros = [ add_version_header(x) for x in [
     "name": "__cpp_lib_constexpr_typeinfo",
     "values": { "c++2b": 202106 },
     "headers": ["typeinfo"],
-    "unimplemented": True,
   }, {
     "name": "__cpp_lib_constexpr_utility",
     "values": { "c++20": 201811 },