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