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