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