1//===------ extensible_rtti.h - Extensible RTTI for ORC RT ------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// \file
10//
11// Provides an extensible RTTI mechanism, that can be used regardless of whether
12// the runtime is built with -frtti or not. This is predominantly used to
13// support error handling.
14//
15// The RTTIRoot class defines methods for comparing type ids. Implementations
16// of these methods can be injected into new classes using the RTTIExtends
17// class template.
18//
19// E.g.
20//
21//   @code{.cpp}
22//   class MyBaseClass : public RTTIExtends<MyBaseClass, RTTIRoot> {
23//   public:
24//     static char ID;
25//     virtual void foo() = 0;
26//   };
27//
28//   class MyDerivedClass1 : public RTTIExtends<MyDerivedClass1, MyBaseClass> {
29//   public:
30//     static char ID;
31//     void foo() override {}
32//   };
33//
34//   class MyDerivedClass2 : public RTTIExtends<MyDerivedClass2, MyBaseClass> {
35//   public:
36//     static char ID;
37//     void foo() override {}
38//   };
39//
40//   char MyBaseClass::ID = 0;
41//   char MyDerivedClass1::ID = 0;
42//   char MyDerivedClass2:: ID = 0;
43//
44//   void fn() {
45//     std::unique_ptr<MyBaseClass> B = std::make_unique<MyDerivedClass1>();
46//     outs() << isa<MyBaseClass>(B) << "\n"; // Outputs "1".
47//     outs() << isa<MyDerivedClass1>(B) << "\n"; // Outputs "1".
48//     outs() << isa<MyDerivedClass2>(B) << "\n"; // Outputs "0'.
49//   }
50//
51//   @endcode
52//
53// Note:
54//   This header was adapted from llvm/Support/ExtensibleRTTI.h, however the
55// data structures are not shared and the code need not be kept in sync.
56//
57//===----------------------------------------------------------------------===//
58
59#ifndef ORC_RT_EXTENSIBLE_RTTI_H
60#define ORC_RT_EXTENSIBLE_RTTI_H
61
62namespace __orc_rt {
63
64template <typename ThisT, typename ParentT> class RTTIExtends;
65
66/// Base class for the extensible RTTI hierarchy.
67///
68/// This class defines virtual methods, dynamicClassID and isA, that enable
69/// type comparisons.
70class RTTIRoot {
71public:
72  virtual ~RTTIRoot() = default;
73
74  /// Returns the class ID for this type.
75  static const void *classID() { return &ID; }
76
77  /// Returns the class ID for the dynamic type of this RTTIRoot instance.
78  virtual const void *dynamicClassID() const = 0;
79
80  /// Returns true if this class's ID matches the given class ID.
81  virtual bool isA(const void *const ClassID) const {
82    return ClassID == classID();
83  }
84
85  /// Check whether this instance is a subclass of QueryT.
86  template <typename QueryT> bool isA() const { return isA(QueryT::classID()); }
87
88  static bool classof(const RTTIRoot *R) { return R->isA<RTTIRoot>(); }
89
90private:
91  virtual void anchor();
92
93  static char ID;
94};
95
96/// Inheritance utility for extensible RTTI.
97///
98/// Supports single inheritance only: A class can only have one
99/// ExtensibleRTTI-parent (i.e. a parent for which the isa<> test will work),
100/// though it can have many non-ExtensibleRTTI parents.
101///
102/// RTTIExtents uses CRTP so the first template argument to RTTIExtends is the
103/// newly introduced type, and the *second* argument is the parent class.
104///
105/// class MyType : public RTTIExtends<MyType, RTTIRoot> {
106/// public:
107///   static char ID;
108/// };
109///
110/// class MyDerivedType : public RTTIExtends<MyDerivedType, MyType> {
111/// public:
112///   static char ID;
113/// };
114///
115template <typename ThisT, typename ParentT> class RTTIExtends : public ParentT {
116public:
117  // Inherit constructors and isA methods from ParentT.
118  using ParentT::isA;
119  using ParentT::ParentT;
120
121  static char ID;
122
123  static const void *classID() { return &ThisT::ID; }
124
125  const void *dynamicClassID() const override { return &ThisT::ID; }
126
127  bool isA(const void *const ClassID) const override {
128    return ClassID == classID() || ParentT::isA(ClassID);
129  }
130
131  static bool classof(const RTTIRoot *R) { return R->isA<ThisT>(); }
132};
133
134template <typename ThisT, typename ParentT>
135char RTTIExtends<ThisT, ParentT>::ID = 0;
136
137/// Returns true if the given value is an instance of the template type
138/// parameter.
139template <typename To, typename From> bool isa(const From &Value) {
140  return To::classof(&Value);
141}
142
143} // end namespace __orc_rt
144
145#endif // ORC_RT_EXTENSIBLE_RTTI_H
146