diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -826,6 +826,7 @@ __type_traits/underlying_type.h __type_traits/unwrap_ref.h __type_traits/void_t.h + __typeinfo/typeinfo.h __undef_macros __utility/as_const.h __utility/auto_cast.h diff --git a/libcxx/include/__exception/exception_ptr.h b/libcxx/include/__exception/exception_ptr.h --- a/libcxx/include/__exception/exception_ptr.h +++ b/libcxx/include/__exception/exception_ptr.h @@ -12,8 +12,10 @@ #include <__config> #include <__exception/operations.h> #include <__memory/addressof.h> +#include <__typeinfo/typeinfo.h> #include #include +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -26,6 +28,20 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr { void* __ptr_; +# if defined(LIBCXX_BUILDING_LIBCXXABI) + template + static inline void __dest_thunk(void* __x) { + static_cast<_Ep*>(__x)->~_Ep(); + } + + static void* __init_native_exception(size_t, std::type_info*, void (*)(void*)) _NOEXCEPT; + static void __free_native_exception(void*) _NOEXCEPT; + static exception_ptr __from_native_exception_pointer(void* __e) _NOEXCEPT; + + template + friend _LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep) _NOEXCEPT; +# endif + public: _LIBCPP_HIDE_FROM_ABI exception_ptr() _NOEXCEPT : __ptr_() {} _LIBCPP_HIDE_FROM_ABI exception_ptr(nullptr_t) _NOEXCEPT : __ptr_() {} @@ -51,11 +67,24 @@ template _LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep __e) _NOEXCEPT { # ifndef _LIBCPP_HAS_NO_EXCEPTIONS +# if defined(LIBCXX_BUILDING_LIBCXXABI) + using _Ep2 = typename decay<_Ep>::type; + void* __ex = exception_ptr::__init_native_exception( + sizeof(_Ep), const_cast(&typeid(_Ep)), exception_ptr::__dest_thunk<_Ep2>); + try { + ::new (__ex) _Ep2(__e); + return exception_ptr::__from_native_exception_pointer(__ex); + } catch (...) { + exception_ptr::__free_native_exception(__ex); + return current_exception(); + } +# else try { throw __e; } catch (...) { return current_exception(); } +# endif # else ((void)__e); std::abort(); diff --git a/libcxx/include/__typeinfo/typeinfo.h b/libcxx/include/__typeinfo/typeinfo.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__typeinfo/typeinfo.h @@ -0,0 +1,333 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___TYPEINFO_TYPEINFO_H +#define _LIBCPP___TYPEINFO_TYPEINFO_H + +#include <__availability> +#include <__config> +#include <__exception/exception.h> +#include <__type_traits/is_constant_evaluated.h> +#include <__verbose_abort> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if defined(_LIBCPP_ABI_VCRUNTIME) +# include +#else + +namespace std // purposefully not using versioning namespace +{ + +# if defined(_LIBCPP_ABI_MICROSOFT) + +class _LIBCPP_EXPORTED_FROM_ABI type_info { + type_info& operator=(const type_info&); + type_info(const type_info&); + + mutable struct { + const char* __undecorated_name; + const char __decorated_name[1]; + } __data; + + int __compare(const type_info& __rhs) const _NOEXCEPT; + +public: + _LIBCPP_AVAILABILITY_TYPEINFO_VTABLE + virtual ~type_info(); + + const char* name() const _NOEXCEPT; + + _LIBCPP_INLINE_VISIBILITY bool before(const type_info& __arg) const _NOEXCEPT { return __compare(__arg) < 0; } + + size_t hash_code() const _NOEXCEPT; + + _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; + } + +# if _LIBCPP_STD_VER <= 17 + _LIBCPP_INLINE_VISIBILITY bool operator!=(const type_info& __arg) const _NOEXCEPT { return !operator==(__arg); } +# endif +}; + +# else // !defined(_LIBCPP_ABI_MICROSOFT) + +// ========================================================================== // +// Implementations +// ========================================================================== // +// ------------------------------------------------------------------------- // +// Unique +// (_LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION = 1) +// ------------------------------------------------------------------------- // +// This implementation of type_info assumes a unique copy of the RTTI for a +// given type inside a program. This is a valid assumption when abiding to the +// Itanium ABI (http://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-components). +// Under this assumption, we can always compare the addresses of the type names +// to implement equality-comparison of type_infos instead of having to perform +// a deep string comparison. +// -------------------------------------------------------------------------- // +// NonUnique +// (_LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION = 2) +// -------------------------------------------------------------------------- // +// This implementation of type_info does not assume there is always a unique +// copy of the RTTI for a given type inside a program. For various reasons +// the linker may have failed to merge every copy of a types RTTI +// (For example: -Bsymbolic or llvm.org/PR37398). Under this assumption, two +// type_infos are equal if their addresses are equal or if a deep string +// comparison is equal. +// -------------------------------------------------------------------------- // +// NonUniqueARMRTTIBit +// (_LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION = 3) +// -------------------------------------------------------------------------- // +// This implementation is specific to ARM64 on Apple platforms. +// +// This implementation of type_info does not assume always a unique copy of +// the RTTI for a given type inside a program. When constructing the type_info, +// the compiler packs the pointer to the type name into a uintptr_t and reserves +// the high bit of that pointer, which is assumed to be free for use under that +// ABI. If that high bit is set, that specific copy of the RTTI can't be assumed +// to be unique within the program. If the high bit is unset, then the RTTI can +// be assumed to be unique within the program. +// +// When comparing type_infos, if both RTTIs can be assumed to be unique, it +// suffices to compare their addresses. If both the RTTIs can't be assumed to +// be unique, we must perform a deep string comparison of the type names. +// However, if one of the RTTIs is guaranteed unique and the other one isn't, +// then both RTTIs are necessarily not to be considered equal. +// +// The intent of this design is to remove the need for weak symbols. Specifically, +// if a type would normally have a default-visibility RTTI emitted as a weak +// symbol, it is given hidden visibility instead and the non-unique bit is set. +// Otherwise, types declared with hidden visibility are always considered to have +// a unique RTTI: the RTTI is emitted with linkonce_odr linkage and is assumed +// to be deduplicated by the linker within the linked image. Across linked image +// boundaries, such types are thus considered different types. + +// This value can be overriden in the __config_site. When it's not overriden, +// we pick a default implementation based on the platform here. +# ifndef _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION + +// Windows and AIX binaries can't merge typeinfos, so use the NonUnique implementation. +# if defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF) +# define _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION 2 + +// On arm64 on Apple platforms, use the special NonUniqueARMRTTIBit implementation. +# elif defined(__APPLE__) && defined(__LP64__) && !defined(__x86_64__) +# define _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION 3 + +// On all other platforms, assume the Itanium C++ ABI and use the Unique implementation. +# else +# define _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION 1 +# endif +# endif + +struct __type_info_implementations { + struct __string_impl_base { + typedef const char* __type_name_t; + _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE _LIBCPP_CONSTEXPR static const char* + __type_name_to_string(__type_name_t __v) _NOEXCEPT { + return __v; + } + _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE _LIBCPP_CONSTEXPR static __type_name_t + __string_to_type_name(const char* __v) _NOEXCEPT { + return __v; + } + }; + + struct __unique_impl : __string_impl_base { + _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE static size_t __hash(__type_name_t __v) _NOEXCEPT { + return reinterpret_cast(__v); + } + _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE static bool + __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { + return __lhs == __rhs; + } + _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE static bool + __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { + return __lhs < __rhs; + } + }; + + struct __non_unique_impl : __string_impl_base { + _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE static size_t __hash(__type_name_t __ptr) _NOEXCEPT { + size_t __hash = 5381; + while (unsigned char __c = static_cast(*__ptr++)) + __hash = (__hash * 33) ^ __c; + return __hash; + } + _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE static bool + __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { + return __lhs == __rhs || __builtin_strcmp(__lhs, __rhs) == 0; + } + _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE static bool + __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { + return __builtin_strcmp(__lhs, __rhs) < 0; + } + }; + + struct __non_unique_arm_rtti_bit_impl { + typedef uintptr_t __type_name_t; + + _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE static const char* + __type_name_to_string(__type_name_t __v) _NOEXCEPT { + return reinterpret_cast(__v & ~__non_unique_rtti_bit::value); + } + _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE static __type_name_t + __string_to_type_name(const char* __v) _NOEXCEPT { + return reinterpret_cast<__type_name_t>(__v); + } + + _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE static size_t __hash(__type_name_t __v) _NOEXCEPT { + if (__is_type_name_unique(__v)) + return __v; + return __non_unique_impl::__hash(__type_name_to_string(__v)); + } + _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE static bool + __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { + if (__lhs == __rhs) + return true; + if (__is_type_name_unique(__lhs) || __is_type_name_unique(__rhs)) + // Either both are unique and have a different address, or one of them + // is unique and the other one isn't. In both cases they are unequal. + return false; + return __builtin_strcmp(__type_name_to_string(__lhs), __type_name_to_string(__rhs)) == 0; + } + _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE static bool + __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { + if (__is_type_name_unique(__lhs) || __is_type_name_unique(__rhs)) + return __lhs < __rhs; + return __builtin_strcmp(__type_name_to_string(__lhs), __type_name_to_string(__rhs)) < 0; + } + + private: + // The unique bit is the top bit. It is expected that __type_name_t is 64 bits when + // this implementation is actually used. + typedef integral_constant<__type_name_t, (1ULL << ((__CHAR_BIT__ * sizeof(__type_name_t)) - 1))> + __non_unique_rtti_bit; + + _LIBCPP_INLINE_VISIBILITY static bool __is_type_name_unique(__type_name_t __lhs) _NOEXCEPT { + return !(__lhs & __non_unique_rtti_bit::value); + } + }; + + typedef +# if _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION == 1 + __unique_impl +# elif _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION == 2 + __non_unique_impl +# elif _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION == 3 + __non_unique_arm_rtti_bit_impl +# else +# error invalid configuration for _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION +# endif + __impl; +}; + +class _LIBCPP_EXPORTED_FROM_ABI type_info { + type_info& operator=(const type_info&); + type_info(const type_info&); + +protected: + typedef __type_info_implementations::__impl __impl; + + __impl::__type_name_t __type_name; + + _LIBCPP_INLINE_VISIBILITY explicit type_info(const char* __n) : __type_name(__impl::__string_to_type_name(__n)) {} + +public: + _LIBCPP_AVAILABILITY_TYPEINFO_VTABLE + virtual ~type_info(); + + _LIBCPP_INLINE_VISIBILITY const char* name() const _NOEXCEPT { return __impl::__type_name_to_string(__type_name); } + + _LIBCPP_INLINE_VISIBILITY bool before(const type_info& __arg) const _NOEXCEPT { + return __impl::__lt(__type_name, __arg.__type_name); + } + + _LIBCPP_INLINE_VISIBILITY size_t hash_code() const _NOEXCEPT { return __impl::__hash(__type_name); } + + _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); + } + +# if _LIBCPP_STD_VER <= 17 + _LIBCPP_INLINE_VISIBILITY bool operator!=(const type_info& __arg) const _NOEXCEPT { return !operator==(__arg); } +# endif +}; +# endif // defined(_LIBCPP_ABI_MICROSOFT) + +class _LIBCPP_EXPORTED_FROM_ABI bad_cast : public exception { +public: + bad_cast() _NOEXCEPT; + _LIBCPP_HIDE_FROM_ABI bad_cast(const bad_cast&) _NOEXCEPT = default; + ~bad_cast() _NOEXCEPT override; + const char* what() const _NOEXCEPT override; +}; + +class _LIBCPP_EXPORTED_FROM_ABI bad_typeid : public exception { +public: + bad_typeid() _NOEXCEPT; + ~bad_typeid() _NOEXCEPT override; + const char* what() const _NOEXCEPT override; +}; + +} // namespace std + +#endif // defined(_LIBCPP_ABI_VCRUNTIME) + +#if defined(_LIBCPP_ABI_VCRUNTIME) && _HAS_EXCEPTIONS == 0 + +namespace std { + +class bad_cast : public exception { +public: + bad_cast() _NOEXCEPT : exception("bad cast") {} + +private: + bad_cast(const char* const __message) _NOEXCEPT : exception(__message) {} +}; + +class bad_typeid : public exception { +public: + bad_typeid() _NOEXCEPT : exception("bad typeid") {} + +private: + bad_typeid(const char* const __message) _NOEXCEPT : exception(__message) {} +}; + +} // namespace std + +#endif // defined(_LIBCPP_ABI_VCRUNTIME) && _HAS_EXCEPTIONS == 0 + +_LIBCPP_BEGIN_NAMESPACE_STD +_LIBCPP_NORETURN inline _LIBCPP_INLINE_VISIBILITY void __throw_bad_cast() { +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS + throw bad_cast(); +#else + _LIBCPP_VERBOSE_ABORT("bad_cast was thrown in -fno-exceptions mode"); +#endif +} +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___TYPEINFO_TYPEINFO_H diff --git a/libcxx/include/libcxx.imp b/libcxx/include/libcxx.imp --- a/libcxx/include/libcxx.imp +++ b/libcxx/include/libcxx.imp @@ -48,6 +48,7 @@ { include: [ "@<__thread/.*>", "private", "", "public" ] }, { include: [ "@<__tuple/.*>", "private", "", "public" ] }, { include: [ "@<__type_traits/.*>", "private", "", "public" ] }, + { include: [ "@<__typeinfo/.*>", "private", "", "public" ] }, { include: [ "@<__utility/.*>", "private", "", "public" ] }, { include: [ "@<__variant/.*>", "private", "", "public" ] }, ] diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1266,6 +1266,11 @@ export std_private_type_traits_is_constant_evaluated } +module std_private_typeinfo_typeinfo [system] { + header "__typeinfo/typeinfo.h" + export * +} + module std_private_exception_exception [system] { header "__exception/exception.h" } module std_private_exception_exception_ptr [system] { header "__exception/exception_ptr.h" diff --git a/libcxx/include/typeinfo b/libcxx/include/typeinfo --- a/libcxx/include/typeinfo +++ b/libcxx/include/typeinfo @@ -57,362 +57,13 @@ */ #include <__assert> // all public C++ headers provide the assertion handler -#include <__availability> #include <__config> -#include <__exception/exception.h> -#include <__type_traits/is_constant_evaluated.h> -#include <__verbose_abort> -#include -#include +#include <__typeinfo/typeinfo.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif -#if defined(_LIBCPP_ABI_VCRUNTIME) -#include -#else - -namespace std // purposefully not using versioning namespace -{ - - -#if defined(_LIBCPP_ABI_MICROSOFT) - -class _LIBCPP_EXPORTED_FROM_ABI type_info -{ - type_info& operator=(const type_info&); - type_info(const type_info&); - - mutable struct { - const char *__undecorated_name; - const char __decorated_name[1]; - } __data; - - int __compare(const type_info &__rhs) const _NOEXCEPT; - -public: - _LIBCPP_AVAILABILITY_TYPEINFO_VTABLE - virtual ~type_info(); - - const char *name() const _NOEXCEPT; - - _LIBCPP_INLINE_VISIBILITY - bool before(const type_info& __arg) const _NOEXCEPT { - return __compare(__arg) < 0; - } - - size_t hash_code() const _NOEXCEPT; - - _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; - } - -#if _LIBCPP_STD_VER <= 17 - _LIBCPP_INLINE_VISIBILITY - bool operator!=(const type_info& __arg) const _NOEXCEPT - { return !operator==(__arg); } -#endif -}; - -#else // !defined(_LIBCPP_ABI_MICROSOFT) - -// ========================================================================== // -// Implementations -// ========================================================================== // -// ------------------------------------------------------------------------- // -// Unique -// (_LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION = 1) -// ------------------------------------------------------------------------- // -// This implementation of type_info assumes a unique copy of the RTTI for a -// given type inside a program. This is a valid assumption when abiding to the -// Itanium ABI (http://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-components). -// Under this assumption, we can always compare the addresses of the type names -// to implement equality-comparison of type_infos instead of having to perform -// a deep string comparison. -// -------------------------------------------------------------------------- // -// NonUnique -// (_LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION = 2) -// -------------------------------------------------------------------------- // -// This implementation of type_info does not assume there is always a unique -// copy of the RTTI for a given type inside a program. For various reasons -// the linker may have failed to merge every copy of a types RTTI -// (For example: -Bsymbolic or llvm.org/PR37398). Under this assumption, two -// type_infos are equal if their addresses are equal or if a deep string -// comparison is equal. -// -------------------------------------------------------------------------- // -// NonUniqueARMRTTIBit -// (_LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION = 3) -// -------------------------------------------------------------------------- // -// This implementation is specific to ARM64 on Apple platforms. -// -// This implementation of type_info does not assume always a unique copy of -// the RTTI for a given type inside a program. When constructing the type_info, -// the compiler packs the pointer to the type name into a uintptr_t and reserves -// the high bit of that pointer, which is assumed to be free for use under that -// ABI. If that high bit is set, that specific copy of the RTTI can't be assumed -// to be unique within the program. If the high bit is unset, then the RTTI can -// be assumed to be unique within the program. -// -// When comparing type_infos, if both RTTIs can be assumed to be unique, it -// suffices to compare their addresses. If both the RTTIs can't be assumed to -// be unique, we must perform a deep string comparison of the type names. -// However, if one of the RTTIs is guaranteed unique and the other one isn't, -// then both RTTIs are necessarily not to be considered equal. -// -// The intent of this design is to remove the need for weak symbols. Specifically, -// if a type would normally have a default-visibility RTTI emitted as a weak -// symbol, it is given hidden visibility instead and the non-unique bit is set. -// Otherwise, types declared with hidden visibility are always considered to have -// a unique RTTI: the RTTI is emitted with linkonce_odr linkage and is assumed -// to be deduplicated by the linker within the linked image. Across linked image -// boundaries, such types are thus considered different types. - -// This value can be overriden in the __config_site. When it's not overriden, -// we pick a default implementation based on the platform here. -#ifndef _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION - - // Windows and AIX binaries can't merge typeinfos, so use the NonUnique implementation. -# if defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF) -# define _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION 2 - - // On arm64 on Apple platforms, use the special NonUniqueARMRTTIBit implementation. -# elif defined(__APPLE__) && defined(__LP64__) && !defined(__x86_64__) -# define _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION 3 - - // On all other platforms, assume the Itanium C++ ABI and use the Unique implementation. -# else -# define _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION 1 -# endif -#endif - -struct __type_info_implementations { - struct __string_impl_base { - typedef const char* __type_name_t; - _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE - _LIBCPP_CONSTEXPR static const char* __type_name_to_string(__type_name_t __v) _NOEXCEPT { - return __v; - } - _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE - _LIBCPP_CONSTEXPR static __type_name_t __string_to_type_name(const char* __v) _NOEXCEPT { - return __v; - } - }; - - struct __unique_impl : __string_impl_base { - _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE - static size_t __hash(__type_name_t __v) _NOEXCEPT { - return reinterpret_cast(__v); - } - _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE - static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { - return __lhs == __rhs; - } - _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE - static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { - return __lhs < __rhs; - } - }; - - struct __non_unique_impl : __string_impl_base { - _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE - static size_t __hash(__type_name_t __ptr) _NOEXCEPT { - size_t __hash = 5381; - while (unsigned char __c = static_cast(*__ptr++)) - __hash = (__hash * 33) ^ __c; - return __hash; - } - _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE - static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { - return __lhs == __rhs || __builtin_strcmp(__lhs, __rhs) == 0; - } - _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE - static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { - return __builtin_strcmp(__lhs, __rhs) < 0; - } - }; - - struct __non_unique_arm_rtti_bit_impl { - typedef uintptr_t __type_name_t; - - _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE - static const char* __type_name_to_string(__type_name_t __v) _NOEXCEPT { - return reinterpret_cast(__v & - ~__non_unique_rtti_bit::value); - } - _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE - static __type_name_t __string_to_type_name(const char* __v) _NOEXCEPT { - return reinterpret_cast<__type_name_t>(__v); - } - - _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE - static size_t __hash(__type_name_t __v) _NOEXCEPT { - if (__is_type_name_unique(__v)) - return __v; - return __non_unique_impl::__hash(__type_name_to_string(__v)); - } - _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE - static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { - if (__lhs == __rhs) - return true; - if (__is_type_name_unique(__lhs) || __is_type_name_unique(__rhs)) - // Either both are unique and have a different address, or one of them - // is unique and the other one isn't. In both cases they are unequal. - return false; - return __builtin_strcmp(__type_name_to_string(__lhs), __type_name_to_string(__rhs)) == 0; - } - _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE - static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { - if (__is_type_name_unique(__lhs) || __is_type_name_unique(__rhs)) - return __lhs < __rhs; - return __builtin_strcmp(__type_name_to_string(__lhs), __type_name_to_string(__rhs)) < 0; - } - - private: - // The unique bit is the top bit. It is expected that __type_name_t is 64 bits when - // this implementation is actually used. - typedef integral_constant<__type_name_t, - (1ULL << ((__CHAR_BIT__ * sizeof(__type_name_t)) - 1))> __non_unique_rtti_bit; - - _LIBCPP_INLINE_VISIBILITY - static bool __is_type_name_unique(__type_name_t __lhs) _NOEXCEPT { - return !(__lhs & __non_unique_rtti_bit::value); - } - }; - - typedef -#if _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION == 1 - __unique_impl -#elif _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION == 2 - __non_unique_impl -#elif _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION == 3 - __non_unique_arm_rtti_bit_impl -#else -# error invalid configuration for _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION -#endif - __impl; -}; - -class _LIBCPP_EXPORTED_FROM_ABI type_info -{ - type_info& operator=(const type_info&); - type_info(const type_info&); - - protected: - typedef __type_info_implementations::__impl __impl; - - __impl::__type_name_t __type_name; - - _LIBCPP_INLINE_VISIBILITY - explicit type_info(const char* __n) - : __type_name(__impl::__string_to_type_name(__n)) {} - -public: - _LIBCPP_AVAILABILITY_TYPEINFO_VTABLE - virtual ~type_info(); - - _LIBCPP_INLINE_VISIBILITY - const char* name() const _NOEXCEPT - { - return __impl::__type_name_to_string(__type_name); - } - - _LIBCPP_INLINE_VISIBILITY - bool before(const type_info& __arg) const _NOEXCEPT - { - return __impl::__lt(__type_name, __arg.__type_name); - } - - _LIBCPP_INLINE_VISIBILITY - size_t hash_code() const _NOEXCEPT - { - return __impl::__hash(__type_name); - } - - _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); - } - -#if _LIBCPP_STD_VER <= 17 - _LIBCPP_INLINE_VISIBILITY - bool operator!=(const type_info& __arg) const _NOEXCEPT - { return !operator==(__arg); } -#endif -}; -#endif // defined(_LIBCPP_ABI_MICROSOFT) - -class _LIBCPP_EXPORTED_FROM_ABI bad_cast - : public exception -{ - public: - bad_cast() _NOEXCEPT; - _LIBCPP_HIDE_FROM_ABI bad_cast(const bad_cast&) _NOEXCEPT = default; - ~bad_cast() _NOEXCEPT override; - const char* what() const _NOEXCEPT override; -}; - -class _LIBCPP_EXPORTED_FROM_ABI bad_typeid - : public exception -{ - public: - bad_typeid() _NOEXCEPT; - ~bad_typeid() _NOEXCEPT override; - const char* what() const _NOEXCEPT override; -}; - -} // namespace std - -#endif // defined(_LIBCPP_ABI_VCRUNTIME) - -#if defined(_LIBCPP_ABI_VCRUNTIME) && _HAS_EXCEPTIONS == 0 - -namespace std { - -class bad_cast : public exception { -public: - bad_cast() _NOEXCEPT : exception("bad cast") {} - -private: - bad_cast(const char* const __message) _NOEXCEPT : exception(__message) {} -}; - -class bad_typeid : public exception { -public: - bad_typeid() _NOEXCEPT : exception("bad typeid") {} - -private: - bad_typeid(const char* const __message) _NOEXCEPT : exception(__message) {} -}; - -} // namespace std - -#endif // defined(_LIBCPP_ABI_VCRUNTIME) && _HAS_EXCEPTIONS == 0 - -_LIBCPP_BEGIN_NAMESPACE_STD -_LIBCPP_NORETURN inline _LIBCPP_INLINE_VISIBILITY -void __throw_bad_cast() -{ -#ifndef _LIBCPP_HAS_NO_EXCEPTIONS - throw bad_cast(); -#else - _LIBCPP_VERBOSE_ABORT("bad_cast was thrown in -fno-exceptions mode"); -#endif -} -_LIBCPP_END_NAMESPACE_STD - #if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20 # include # include diff --git a/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp b/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp --- a/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp +++ b/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp @@ -13,8 +13,9 @@ namespace std { -exception_ptr::~exception_ptr() noexcept { - __cxa_decrement_exception_refcount(__ptr_); +exception_ptr::~exception_ptr() noexcept +{ + __cxa_decrement_exception_refcount(__ptr_); } exception_ptr::exception_ptr(const exception_ptr& other) noexcept @@ -34,6 +35,26 @@ return *this; } +void *exception_ptr::__init_native_exception(size_t size, type_info *tinfo, void (*dest)(void *)) noexcept +{ + void *__ex = __cxa_allocate_exception(size); + (void)__cxa_init_primary_exception(__ex, tinfo, dest); + return __ex; +} + +void exception_ptr::__free_native_exception(void *thrown_object) noexcept +{ + __cxa_free_exception(thrown_object); +} + +exception_ptr exception_ptr::__from_native_exception_pointer(void *__e) noexcept { + exception_ptr ptr; + ptr.__ptr_ = __e; + __cxa_increment_exception_refcount(ptr.__ptr_); + + return ptr; +} + nested_exception::nested_exception() noexcept : __ptr_(current_exception()) { diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv --- a/libcxx/test/libcxx/transitive_includes/cxx03.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv @@ -217,6 +217,7 @@ deque typeinfo deque version exception cstddef +exception cstdint exception cstdlib exception type_traits exception version diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv --- a/libcxx/test/libcxx/transitive_includes/cxx11.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv @@ -217,6 +217,7 @@ deque typeinfo deque version exception cstddef +exception cstdint exception cstdlib exception type_traits exception version diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv --- a/libcxx/test/libcxx/transitive_includes/cxx14.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv @@ -217,6 +217,7 @@ deque typeinfo deque version exception cstddef +exception cstdint exception cstdlib exception type_traits exception version diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv --- a/libcxx/test/libcxx/transitive_includes/cxx17.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv @@ -217,6 +217,7 @@ deque typeinfo deque version exception cstddef +exception cstdint exception cstdlib exception type_traits exception version diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv --- a/libcxx/test/libcxx/transitive_includes/cxx20.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv @@ -224,6 +224,7 @@ deque typeinfo deque version exception cstddef +exception cstdint exception cstdlib exception type_traits exception version diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv --- a/libcxx/test/libcxx/transitive_includes/cxx23.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv @@ -152,7 +152,9 @@ deque tuple deque version exception cstddef +exception cstdint exception cstdlib +exception type_traits exception version execution cstddef execution version @@ -286,6 +288,7 @@ future stdexcept future string future thread +future type_traits future typeinfo future version initializer_list cstddef diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv --- a/libcxx/test/libcxx/transitive_includes/cxx26.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv @@ -152,7 +152,9 @@ deque tuple deque version exception cstddef +exception cstdint exception cstdlib +exception type_traits exception version execution cstddef execution version @@ -286,6 +288,7 @@ future stdexcept future string future thread +future type_traits future typeinfo future version initializer_list cstddef diff --git a/libcxx/utils/data/ignore_format.txt b/libcxx/utils/data/ignore_format.txt --- a/libcxx/utils/data/ignore_format.txt +++ b/libcxx/utils/data/ignore_format.txt @@ -468,6 +468,7 @@ libcxx/include/__tuple/tuple_like_ext.h libcxx/include/__tuple/tuple_size.h libcxx/include/__tuple/tuple_types.h +libcxx/include/__typeinfo/typeinfo.h libcxx/include/typeindex libcxx/include/typeinfo libcxx/include/uchar.h diff --git a/libcxxabi/include/cxxabi.h b/libcxxabi/include/cxxabi.h --- a/libcxxabi/include/cxxabi.h +++ b/libcxxabi/include/cxxabi.h @@ -36,6 +36,9 @@ // runtime routines use C calling conventions, but are in __cxxabiv1 namespace namespace __cxxabiv1 { + +struct __cxa_exception; + extern "C" { // 2.4.2 Allocating the Exception Object @@ -43,6 +46,9 @@ __cxa_allocate_exception(size_t thrown_size) throw(); extern _LIBCXXABI_FUNC_VIS void __cxa_free_exception(void *thrown_exception) throw(); +// This function is an llvm extension +extern _LIBCXXABI_FUNC_VIS __cxa_exception* +__cxa_init_primary_exception(void* object, std::type_info* tinfo, void(_LIBCXXABI_DTOR_FUNC* dest)(void*)) throw(); // 2.4.3 Throwing the Exception Object extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void diff --git a/libcxxabi/src/cxa_exception.cpp b/libcxxabi/src/cxa_exception.cpp --- a/libcxxabi/src/cxa_exception.cpp +++ b/libcxxabi/src/cxa_exception.cpp @@ -206,6 +206,19 @@ __aligned_free_with_fallback((void *)raw_buffer); } +__cxa_exception* __cxa_init_primary_exception(void* object, std::type_info* tinfo, + void(_LIBCXXABI_DTOR_FUNC* dest)(void*)) throw() { + __cxa_exception* exception_header = cxa_exception_from_thrown_object(object); + exception_header->referenceCount = 0; + exception_header->unexpectedHandler = std::get_unexpected(); + exception_header->terminateHandler = std::get_terminate(); + exception_header->exceptionType = tinfo; + exception_header->exceptionDestructor = dest; + setOurExceptionClass(&exception_header->unwindHeader); + exception_header->unwindHeader.exception_cleanup = exception_cleanup_func; + + return exception_header; +} // This function shall allocate a __cxa_dependent_exception and // return a pointer to it. (Really to the object, not past its' end). @@ -255,18 +268,11 @@ */ void __cxa_throw(void *thrown_object, std::type_info *tinfo, void (_LIBCXXABI_DTOR_FUNC *dest)(void *)) { - __cxa_eh_globals *globals = __cxa_get_globals(); - __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); - - exception_header->unexpectedHandler = std::get_unexpected(); - exception_header->terminateHandler = std::get_terminate(); - exception_header->exceptionType = tinfo; - exception_header->exceptionDestructor = dest; - setOurExceptionClass(&exception_header->unwindHeader); - exception_header->referenceCount = 1; // This is a newly allocated exception, no need for thread safety. + __cxa_eh_globals* globals = __cxa_get_globals(); globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local - exception_header->unwindHeader.exception_cleanup = exception_cleanup_func; + __cxa_exception* exception_header = __cxa_init_primary_exception(thrown_object, tinfo, dest); + exception_header->referenceCount = 1; // This is a newly allocated exception, no need for thread safety. #if __has_feature(address_sanitizer) // Inform the ASan runtime that now might be a good time to clean stuff up.