diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -316,7 +316,7 @@ ------------------------------------------------- ----------------- ``__cpp_lib_constexpr_memory`` ``202202L`` ------------------------------------------------- ----------------- - ``__cpp_lib_constexpr_typeinfo`` *unimplemented* + ``__cpp_lib_constexpr_typeinfo`` ``202106L`` ------------------------------------------------- ----------------- ``__cpp_lib_expected`` ``202202L`` ------------------------------------------------- ----------------- diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -38,6 +38,8 @@ Implemented Papers ------------------ +- P1328R1 - `constexpr type_info::operator==()` + Improvements and New Features ----------------------------- diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv --- a/libcxx/docs/Status/Cxx2bPapers.csv +++ b/libcxx/docs/Status/Cxx2bPapers.csv @@ -14,7 +14,7 @@ "`P0401R6 `__","LWG","Providing size feedback in the Allocator interface","June 2021","|Complete|","15.0" "`P0448R4 `__","LWG","A strstream replacement using span as buffer","June 2021","","" "`P1132R8 `__","LWG","out_ptr - a scalable output pointer abstraction","June 2021","","" -"`P1328R1 `__","LWG","Making std::type_info::operator== constexpr","June 2021","","" +"`P1328R1 `__","LWG","Making std::type_info::operator== constexpr","June 2021","|Complete|","17.0" "`P1425R4 `__","LWG","Iterators pair constructors for stack and queue","June 2021","|Complete|","14.0","|ranges|" "`P1518R2 `__","LWG","Stop overconstraining allocators in container deduction guides","June 2021","|Complete|","13.0" "`P1659R3 `__","LWG","starts_with and ends_with","June 2021","","","|ranges|" diff --git a/libcxx/include/typeinfo b/libcxx/include/typeinfo --- a/libcxx/include/typeinfo +++ b/libcxx/include/typeinfo @@ -21,7 +21,7 @@ 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 @@ #include <__assert> // all public C++ headers provide the assertion handler #include <__availability> #include <__config> +#include <__type_traits/is_constant_evaluated.h> #include #include #include @@ -104,8 +105,13 @@ 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 @@ 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); } diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -392,7 +392,7 @@ // # 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 diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/typeinfo.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/typeinfo.version.compile.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/typeinfo.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/typeinfo.version.compile.pass.cpp @@ -48,17 +48,11 @@ #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 diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -3988,17 +3988,11 @@ # 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 --- /dev/null +++ b/libcxx/test/std/language.support/support.rtti/type.info/type_info.equal.pass.cpp @@ -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 +#include + +#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; +} diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -267,7 +267,6 @@ "name": "__cpp_lib_constexpr_typeinfo", "values": { "c++2b": 202106 }, "headers": ["typeinfo"], - "unimplemented": True, }, { "name": "__cpp_lib_constexpr_utility", "values": { "c++20": 201811 },