1// -*- C++ -*-
2//===-------------------------- typeinfo ----------------------------------===//
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;
25    bool operator!=(const type_info& rhs) const noexcept;
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 <__config>
60#include <exception>
61#include <cstddef>
62#include <cstdint>
63#include <type_traits>
64#ifdef _LIBCPP_NO_EXCEPTIONS
65#include <cstdlib>
66#endif
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_EXCEPTION_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
108    bool operator==(const type_info& __arg) const _NOEXCEPT {
109      return __compare(__arg) == 0;
110    }
111
112    _LIBCPP_INLINE_VISIBILITY
113    bool operator!=(const type_info& __arg) const _NOEXCEPT
114    { return !operator==(__arg); }
115};
116
117#else // !defined(_LIBCPP_ABI_MICROSOFT)
118
119// ========================================================================== //
120//                           Implementations
121// ========================================================================== //
122// ------------------------------------------------------------------------- //
123//                               Unique
124// ------------------------------------------------------------------------- //
125// This implementation of type_info assumes a unique copy of the RTTI for a
126// given type inside a program. This is a valid assumption when abiding to
127// Itanium ABI (http://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-components).
128// Under this assumption, we can always compare the addresses of the type names
129// to implement equality-comparison of type_infos instead of having to perform
130// a deep string comparison.
131// -------------------------------------------------------------------------- //
132//                             NonUnique
133// -------------------------------------------------------------------------- //
134// This implementation of type_info does not assume there is always a unique
135// copy of the RTTI for a given type inside a program. For various reasons
136// the linker may have failed to merge every copy of a types RTTI
137// (For example: -Bsymbolic or llvm.org/PR37398). Under this assumption, two
138// type_infos are equal if their addresses are equal or if a deep string
139// comparison is equal.
140// -------------------------------------------------------------------------- //
141//                          NonUniqueARMRTTIBit
142// -------------------------------------------------------------------------- //
143// This implementation of type_info does not assume always a unique copy of
144// the RTTI for a given type inside a program. It packs the pointer to the
145// type name into a uintptr_t and reserves the high bit of that pointer (which
146// is assumed to be free for use under the ABI in use) to represent whether
147// that specific copy of the RTTI can be assumed unique inside the program.
148// To implement equality-comparison of type_infos, we check whether BOTH
149// type_infos are guaranteed unique, and if so, we simply compare the addresses
150// of their type names instead of doing a deep string comparison, which is
151// faster. If at least one of the type_infos can't guarantee uniqueness, we
152// have no choice but to fall back to a deep string comparison.
153//
154// This implementation is specific to ARM64 on Apple platforms.
155//
156// Note that the compiler is the one setting (or unsetting) the high bit of
157// the pointer when it constructs the type_info, depending on whether it can
158// guarantee uniqueness for that specific type_info.
159
160struct __type_info_implementations {
161  struct __string_impl_base {
162    typedef const char* __type_name_t;
163    _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE
164    _LIBCPP_CONSTEXPR static const char* __type_name_to_string(__type_name_t __v) _NOEXCEPT {
165      return __v;
166    }
167    _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE
168    _LIBCPP_CONSTEXPR static __type_name_t __string_to_type_name(const char* __v) _NOEXCEPT {
169      return __v;
170    }
171  };
172
173  struct __unique_impl : __string_impl_base {
174    _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE
175    static size_t __hash(__type_name_t __v) _NOEXCEPT {
176      return reinterpret_cast<size_t>(__v);
177    }
178    _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE
179    static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT {
180      return __lhs == __rhs;
181    }
182    _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE
183    static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT {
184      return __lhs < __rhs;
185    }
186  };
187
188  struct __non_unique_impl : __string_impl_base {
189    _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE
190    static size_t __hash(__type_name_t __ptr) _NOEXCEPT {
191      size_t __hash = 5381;
192      while (unsigned char __c = static_cast<unsigned char>(*__ptr++))
193        __hash = (__hash * 33) ^ __c;
194      return __hash;
195    }
196    _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE
197    static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT {
198      return __lhs == __rhs || __builtin_strcmp(__lhs, __rhs) == 0;
199    }
200    _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE
201    static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT {
202      return __builtin_strcmp(__lhs, __rhs) < 0;
203    }
204  };
205
206  struct __non_unique_arm_rtti_bit_impl {
207    typedef uintptr_t __type_name_t;
208
209    _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE
210    static const char* __type_name_to_string(__type_name_t __v) _NOEXCEPT {
211      return reinterpret_cast<const char*>(__v &
212          ~__non_unique_rtti_bit::value);
213    }
214    _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE
215    static __type_name_t __string_to_type_name(const char* __v) _NOEXCEPT {
216      return reinterpret_cast<__type_name_t>(__v);
217    }
218
219    _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE
220    static size_t __hash(__type_name_t __v) _NOEXCEPT {
221      if (__is_type_name_unique(__v))
222        return reinterpret_cast<size_t>(__v);
223      return __non_unique_impl::__hash(__type_name_to_string(__v));
224    }
225    _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE
226    static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT {
227      if (__lhs == __rhs)
228        return true;
229      if (__is_type_name_unique(__lhs, __rhs))
230        return false;
231      return __builtin_strcmp(__type_name_to_string(__lhs), __type_name_to_string(__rhs)) == 0;
232    }
233    _LIBCPP_INLINE_VISIBILITY _LIBCPP_ALWAYS_INLINE
234    static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT {
235      if (__is_type_name_unique(__lhs, __rhs))
236        return __lhs < __rhs;
237      return __builtin_strcmp(__type_name_to_string(__lhs), __type_name_to_string(__rhs)) < 0;
238    }
239
240   private:
241    // The unique bit is the top bit. It is expected that __type_name_t is 64 bits when
242    // this implementation is actually used.
243    typedef std::integral_constant<__type_name_t,
244      (1ULL << ((__CHAR_BIT__ * sizeof(__type_name_t)) - 1))> __non_unique_rtti_bit;
245
246    _LIBCPP_INLINE_VISIBILITY
247    static bool __is_type_name_unique(__type_name_t __lhs) _NOEXCEPT {
248      return !(__lhs & __non_unique_rtti_bit::value);
249    }
250    _LIBCPP_INLINE_VISIBILITY
251    static bool __is_type_name_unique(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT {
252      return !((__lhs & __rhs) & __non_unique_rtti_bit::value);
253    }
254  };
255
256  typedef
257#if defined(__APPLE__) && defined(__LP64__) && !defined(__x86_64__)
258    __non_unique_arm_rtti_bit_impl
259#elif _LIBCPP_HAS_MERGED_TYPEINFO_NAMES_DEFAULT == 0
260    __non_unique_impl
261#elif _LIBCPP_HAS_MERGED_TYPEINFO_NAMES_DEFAULT == 1
262    __unique_impl
263#else
264#   error invalid configuration for _LIBCPP_HAS_MERGED_TYPEINFO_NAMES_DEFAULT
265#endif
266     __impl;
267};
268
269class _LIBCPP_EXCEPTION_ABI type_info
270{
271  type_info& operator=(const type_info&);
272  type_info(const type_info&);
273
274 protected:
275    typedef __type_info_implementations::__impl __impl;
276
277    __impl::__type_name_t __type_name;
278
279    _LIBCPP_INLINE_VISIBILITY
280    explicit type_info(const char* __n)
281      : __type_name(__impl::__string_to_type_name(__n)) {}
282
283public:
284    _LIBCPP_AVAILABILITY_TYPEINFO_VTABLE
285    virtual ~type_info();
286
287    _LIBCPP_INLINE_VISIBILITY
288    const char* name() const _NOEXCEPT
289    {
290      return __impl::__type_name_to_string(__type_name);
291    }
292
293    _LIBCPP_INLINE_VISIBILITY
294    bool before(const type_info& __arg) const _NOEXCEPT
295    {
296      return __impl::__lt(__type_name, __arg.__type_name);
297    }
298
299    _LIBCPP_INLINE_VISIBILITY
300    size_t hash_code() const _NOEXCEPT
301    {
302      return __impl::__hash(__type_name);
303    }
304
305    _LIBCPP_INLINE_VISIBILITY
306    bool operator==(const type_info& __arg) const _NOEXCEPT
307    {
308      return __impl::__eq(__type_name, __arg.__type_name);
309    }
310
311    _LIBCPP_INLINE_VISIBILITY
312    bool operator!=(const type_info& __arg) const _NOEXCEPT
313    { return !operator==(__arg); }
314};
315#endif // defined(_LIBCPP_ABI_MICROSOFT)
316
317class _LIBCPP_EXCEPTION_ABI bad_cast
318    : public exception
319{
320 public:
321  bad_cast() _NOEXCEPT;
322  virtual ~bad_cast() _NOEXCEPT;
323  virtual const char* what() const _NOEXCEPT;
324};
325
326class _LIBCPP_EXCEPTION_ABI bad_typeid
327    : public exception
328{
329 public:
330  bad_typeid() _NOEXCEPT;
331  virtual ~bad_typeid() _NOEXCEPT;
332  virtual const char* what() const _NOEXCEPT;
333};
334
335}  // std
336
337#endif // defined(_LIBCPP_ABI_VCRUNTIME)
338
339_LIBCPP_BEGIN_NAMESPACE_STD
340_LIBCPP_NORETURN inline _LIBCPP_INLINE_VISIBILITY
341void __throw_bad_cast()
342{
343#ifndef _LIBCPP_NO_EXCEPTIONS
344    throw bad_cast();
345#else
346    _VSTD::abort();
347#endif
348}
349_LIBCPP_END_NAMESPACE_STD
350
351#endif  // __LIBCPP_TYPEINFO
352