1// -*- C++ -*- 2//===----------------------------------------------------------------------===// 3// 4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5// See https://llvm.org/LICENSE.txt for license information. 6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7// 8//===----------------------------------------------------------------------===// 9 10#ifndef _LIBCPP_TYPEINFO 11#define _LIBCPP_TYPEINFO 12 13/* 14 15 typeinfo synopsis 16 17namespace std { 18 19class type_info 20{ 21public: 22 virtual ~type_info(); 23 24 bool operator==(const type_info& rhs) const noexcept; // constexpr since C++23 25 bool operator!=(const type_info& rhs) const noexcept; // removed in C++20 26 27 bool before(const type_info& rhs) const noexcept; 28 size_t hash_code() const noexcept; 29 const char* name() const noexcept; 30 31 type_info(const type_info& rhs) = delete; 32 type_info& operator=(const type_info& rhs) = delete; 33}; 34 35class bad_cast 36 : public exception 37{ 38public: 39 bad_cast() noexcept; 40 bad_cast(const bad_cast&) noexcept; 41 bad_cast& operator=(const bad_cast&) noexcept; 42 virtual const char* what() const noexcept; 43}; 44 45class bad_typeid 46 : public exception 47{ 48public: 49 bad_typeid() noexcept; 50 bad_typeid(const bad_typeid&) noexcept; 51 bad_typeid& operator=(const bad_typeid&) noexcept; 52 virtual const char* what() const noexcept; 53}; 54 55} // std 56 57*/ 58 59#include <__assert> // all public C++ headers provide the assertion handler 60#include <__availability> 61#include <__config> 62#include <__exception/exception.h> 63#include <__type_traits/is_constant_evaluated.h> 64#include <__verbose_abort> 65#include <cstddef> 66#include <cstdint> 67 68#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 69# pragma GCC system_header 70#endif 71 72#if defined(_LIBCPP_ABI_VCRUNTIME) 73#include <vcruntime_typeinfo.h> 74#else 75 76namespace std // purposefully not using versioning namespace 77{ 78 79 80#if defined(_LIBCPP_ABI_MICROSOFT) 81 82class _LIBCPP_EXPORTED_FROM_ABI type_info 83{ 84 type_info& operator=(const type_info&); 85 type_info(const type_info&); 86 87 mutable struct { 88 const char *__undecorated_name; 89 const char __decorated_name[1]; 90 } __data; 91 92 int __compare(const type_info &__rhs) const _NOEXCEPT; 93 94public: 95 virtual ~type_info(); 96 97 const char *name() const _NOEXCEPT; 98 99 _LIBCPP_HIDE_FROM_ABI 100 bool before(const type_info& __arg) const _NOEXCEPT { 101 return __compare(__arg) < 0; 102 } 103 104 size_t hash_code() const _NOEXCEPT; 105 106 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 107 bool operator==(const type_info& __arg) const _NOEXCEPT { 108 // When evaluated in a constant expression, both type infos simply can't come 109 // from different translation units, so it is sufficient to compare their addresses. 110 if (__libcpp_is_constant_evaluated()) { 111 return this == &__arg; 112 } 113 return __compare(__arg) == 0; 114 } 115 116#if _LIBCPP_STD_VER <= 17 117 _LIBCPP_HIDE_FROM_ABI 118 bool operator!=(const type_info& __arg) const _NOEXCEPT 119 { return !operator==(__arg); } 120#endif 121}; 122 123#else // !defined(_LIBCPP_ABI_MICROSOFT) 124 125// ========================================================================== // 126// Implementations 127// ========================================================================== // 128// ------------------------------------------------------------------------- // 129// Unique 130// (_LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION = 1) 131// ------------------------------------------------------------------------- // 132// This implementation of type_info assumes a unique copy of the RTTI for a 133// given type inside a program. This is a valid assumption when abiding to the 134// Itanium ABI (http://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-components). 135// Under this assumption, we can always compare the addresses of the type names 136// to implement equality-comparison of type_infos instead of having to perform 137// a deep string comparison. 138// -------------------------------------------------------------------------- // 139// NonUnique 140// (_LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION = 2) 141// -------------------------------------------------------------------------- // 142// This implementation of type_info does not assume there is always a unique 143// copy of the RTTI for a given type inside a program. For various reasons 144// the linker may have failed to merge every copy of a types RTTI 145// (For example: -Bsymbolic or llvm.org/PR37398). Under this assumption, two 146// type_infos are equal if their addresses are equal or if a deep string 147// comparison is equal. 148// -------------------------------------------------------------------------- // 149// NonUniqueARMRTTIBit 150// (_LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION = 3) 151// -------------------------------------------------------------------------- // 152// This implementation is specific to ARM64 on Apple platforms. 153// 154// This implementation of type_info does not assume always a unique copy of 155// the RTTI for a given type inside a program. When constructing the type_info, 156// the compiler packs the pointer to the type name into a uintptr_t and reserves 157// the high bit of that pointer, which is assumed to be free for use under that 158// ABI. If that high bit is set, that specific copy of the RTTI can't be assumed 159// to be unique within the program. If the high bit is unset, then the RTTI can 160// be assumed to be unique within the program. 161// 162// When comparing type_infos, if both RTTIs can be assumed to be unique, it 163// suffices to compare their addresses. If both the RTTIs can't be assumed to 164// be unique, we must perform a deep string comparison of the type names. 165// However, if one of the RTTIs is guaranteed unique and the other one isn't, 166// then both RTTIs are necessarily not to be considered equal. 167// 168// The intent of this design is to remove the need for weak symbols. Specifically, 169// if a type would normally have a default-visibility RTTI emitted as a weak 170// symbol, it is given hidden visibility instead and the non-unique bit is set. 171// Otherwise, types declared with hidden visibility are always considered to have 172// a unique RTTI: the RTTI is emitted with linkonce_odr linkage and is assumed 173// to be deduplicated by the linker within the linked image. Across linked image 174// boundaries, such types are thus considered different types. 175 176// This value can be overriden in the __config_site. When it's not overriden, 177// we pick a default implementation based on the platform here. 178#ifndef _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION 179 180 // Windows and AIX binaries can't merge typeinfos, so use the NonUnique implementation. 181# if defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF) 182# define _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION 2 183 184 // On arm64 on Apple platforms, use the special NonUniqueARMRTTIBit implementation. 185# elif defined(__APPLE__) && defined(__LP64__) && !defined(__x86_64__) 186# define _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION 3 187 188 // On all other platforms, assume the Itanium C++ ABI and use the Unique implementation. 189# else 190# define _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION 1 191# endif 192#endif 193 194struct __type_info_implementations { 195 struct __string_impl_base { 196 typedef const char* __type_name_t; 197 _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE 198 _LIBCPP_CONSTEXPR static const char* __type_name_to_string(__type_name_t __v) _NOEXCEPT { 199 return __v; 200 } 201 _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE 202 _LIBCPP_CONSTEXPR static __type_name_t __string_to_type_name(const char* __v) _NOEXCEPT { 203 return __v; 204 } 205 }; 206 207 struct __unique_impl : __string_impl_base { 208 _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE 209 static size_t __hash(__type_name_t __v) _NOEXCEPT { 210 return reinterpret_cast<size_t>(__v); 211 } 212 _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE 213 static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { 214 return __lhs == __rhs; 215 } 216 _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE 217 static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { 218 return __lhs < __rhs; 219 } 220 }; 221 222 struct __non_unique_impl : __string_impl_base { 223 _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE 224 static size_t __hash(__type_name_t __ptr) _NOEXCEPT { 225 size_t __hash = 5381; 226 while (unsigned char __c = static_cast<unsigned char>(*__ptr++)) 227 __hash = (__hash * 33) ^ __c; 228 return __hash; 229 } 230 _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE 231 static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { 232 return __lhs == __rhs || __builtin_strcmp(__lhs, __rhs) == 0; 233 } 234 _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE 235 static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { 236 return __builtin_strcmp(__lhs, __rhs) < 0; 237 } 238 }; 239 240 struct __non_unique_arm_rtti_bit_impl { 241 typedef uintptr_t __type_name_t; 242 243 _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE 244 static const char* __type_name_to_string(__type_name_t __v) _NOEXCEPT { 245 return reinterpret_cast<const char*>(__v & 246 ~__non_unique_rtti_bit::value); 247 } 248 _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE 249 static __type_name_t __string_to_type_name(const char* __v) _NOEXCEPT { 250 return reinterpret_cast<__type_name_t>(__v); 251 } 252 253 _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE 254 static size_t __hash(__type_name_t __v) _NOEXCEPT { 255 if (__is_type_name_unique(__v)) 256 return __v; 257 return __non_unique_impl::__hash(__type_name_to_string(__v)); 258 } 259 _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE 260 static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { 261 if (__lhs == __rhs) 262 return true; 263 if (__is_type_name_unique(__lhs) || __is_type_name_unique(__rhs)) 264 // Either both are unique and have a different address, or one of them 265 // is unique and the other one isn't. In both cases they are unequal. 266 return false; 267 return __builtin_strcmp(__type_name_to_string(__lhs), __type_name_to_string(__rhs)) == 0; 268 } 269 _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE 270 static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { 271 if (__is_type_name_unique(__lhs) || __is_type_name_unique(__rhs)) 272 return __lhs < __rhs; 273 return __builtin_strcmp(__type_name_to_string(__lhs), __type_name_to_string(__rhs)) < 0; 274 } 275 276 private: 277 // The unique bit is the top bit. It is expected that __type_name_t is 64 bits when 278 // this implementation is actually used. 279 typedef integral_constant<__type_name_t, 280 (1ULL << ((__CHAR_BIT__ * sizeof(__type_name_t)) - 1))> __non_unique_rtti_bit; 281 282 _LIBCPP_HIDE_FROM_ABI 283 static bool __is_type_name_unique(__type_name_t __lhs) _NOEXCEPT { 284 return !(__lhs & __non_unique_rtti_bit::value); 285 } 286 }; 287 288 typedef 289#if _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION == 1 290 __unique_impl 291#elif _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION == 2 292 __non_unique_impl 293#elif _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION == 3 294 __non_unique_arm_rtti_bit_impl 295#else 296# error invalid configuration for _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION 297#endif 298 __impl; 299}; 300 301class _LIBCPP_EXPORTED_FROM_ABI type_info 302{ 303 type_info& operator=(const type_info&); 304 type_info(const type_info&); 305 306 protected: 307 typedef __type_info_implementations::__impl __impl; 308 309 __impl::__type_name_t __type_name; 310 311 _LIBCPP_HIDE_FROM_ABI 312 explicit type_info(const char* __n) 313 : __type_name(__impl::__string_to_type_name(__n)) {} 314 315public: 316 virtual ~type_info(); 317 318 _LIBCPP_HIDE_FROM_ABI 319 const char* name() const _NOEXCEPT 320 { 321 return __impl::__type_name_to_string(__type_name); 322 } 323 324 _LIBCPP_HIDE_FROM_ABI 325 bool before(const type_info& __arg) const _NOEXCEPT 326 { 327 return __impl::__lt(__type_name, __arg.__type_name); 328 } 329 330 _LIBCPP_HIDE_FROM_ABI 331 size_t hash_code() const _NOEXCEPT 332 { 333 return __impl::__hash(__type_name); 334 } 335 336 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 337 bool operator==(const type_info& __arg) const _NOEXCEPT 338 { 339 // When evaluated in a constant expression, both type infos simply can't come 340 // from different translation units, so it is sufficient to compare their addresses. 341 if (__libcpp_is_constant_evaluated()) { 342 return this == &__arg; 343 } 344 return __impl::__eq(__type_name, __arg.__type_name); 345 } 346 347#if _LIBCPP_STD_VER <= 17 348 _LIBCPP_HIDE_FROM_ABI 349 bool operator!=(const type_info& __arg) const _NOEXCEPT 350 { return !operator==(__arg); } 351#endif 352}; 353#endif // defined(_LIBCPP_ABI_MICROSOFT) 354 355class _LIBCPP_EXPORTED_FROM_ABI bad_cast 356 : public exception 357{ 358 public: 359 bad_cast() _NOEXCEPT; 360 _LIBCPP_HIDE_FROM_ABI bad_cast(const bad_cast&) _NOEXCEPT = default; 361 _LIBCPP_HIDE_FROM_ABI bad_cast& operator=(const bad_cast&) _NOEXCEPT = default; 362 ~bad_cast() _NOEXCEPT override; 363 const char* what() const _NOEXCEPT override; 364}; 365 366class _LIBCPP_EXPORTED_FROM_ABI bad_typeid 367 : public exception 368{ 369 public: 370 bad_typeid() _NOEXCEPT; 371 _LIBCPP_HIDE_FROM_ABI bad_typeid(const bad_typeid&) _NOEXCEPT = default; 372 _LIBCPP_HIDE_FROM_ABI bad_typeid& operator=(const bad_typeid&) _NOEXCEPT = default; 373 ~bad_typeid() _NOEXCEPT override; 374 const char* what() const _NOEXCEPT override; 375}; 376 377} // namespace std 378 379#endif // defined(_LIBCPP_ABI_VCRUNTIME) 380 381#if defined(_LIBCPP_ABI_VCRUNTIME) && _HAS_EXCEPTIONS == 0 382 383namespace std { 384 385class bad_cast : public exception { 386public: 387 bad_cast() _NOEXCEPT : exception("bad cast") {} 388 389private: 390 bad_cast(const char* const __message) _NOEXCEPT : exception(__message) {} 391}; 392 393class bad_typeid : public exception { 394public: 395 bad_typeid() _NOEXCEPT : exception("bad typeid") {} 396 397private: 398 bad_typeid(const char* const __message) _NOEXCEPT : exception(__message) {} 399}; 400 401} // namespace std 402 403#endif // defined(_LIBCPP_ABI_VCRUNTIME) && _HAS_EXCEPTIONS == 0 404 405_LIBCPP_BEGIN_NAMESPACE_STD 406_LIBCPP_NORETURN inline _LIBCPP_HIDE_FROM_ABI 407void __throw_bad_cast() 408{ 409#ifndef _LIBCPP_HAS_NO_EXCEPTIONS 410 throw bad_cast(); 411#else 412 _LIBCPP_VERBOSE_ABORT("bad_cast was thrown in -fno-exceptions mode"); 413#endif 414} 415_LIBCPP_END_NAMESPACE_STD 416 417#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20 418# include <cstdlib> 419# include <exception> 420# include <type_traits> 421#endif 422 423#endif // _LIBCPP_TYPEINFO 424