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