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