1//===-- llvm/Support/ExtensibleRTTI.h - ExtensibleRTTI support --*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// \file
11//
12// Defines an extensible RTTI mechanism designed to work with Casting.h.
13//
14// Extensible RTTI differs from LLVM's primary RTTI mechanism (see
15// llvm.org/docs/HowToSetUpLLVMStyleRTTI.html) by supporting open type
16// hierarchies, where new types can be added from outside libraries without
17// needing to change existing code. LLVM's primary RTTI mechanism should be
18// preferred where possible, but where open hierarchies are needed this system
19// can be used.
20//
21// The RTTIRoot class defines methods for comparing type ids. Implementations
22// of these methods can be injected into new classes using the RTTIExtends
23// class template.
24//
25// E.g.
26//
27// @code{.cpp}
28// class MyBaseClass : public RTTIExtends<MyBaseClass, RTTIRoot> {
29// public:
30// static char ID;
31// virtual void foo() = 0;
32// };
33//
34// class MyDerivedClass1 : public RTTIExtends<MyDerivedClass1, MyBaseClass> {
35// public:
36// static char ID;
37// void foo() override {}
38// };
39//
40// class MyDerivedClass2 : public RTTIExtends<MyDerivedClass2, MyBaseClass> {
41// public:
42// static char ID;
43// void foo() override {}
44// };
45//
46// char MyBaseClass::ID = 0;
47// char MyDerivedClass1::ID = 0;
48// char MyDerivedClass2:: ID = 0;
49//
50// void fn() {
51// std::unique_ptr<MyBaseClass> B = llvm::make_unique<MyDerivedClass1>();
52// llvm::outs() << isa<MyBaseClass>(B) << "\n"; // Outputs "1".
53// llvm::outs() << isa<MyDerivedClass1>(B) << "\n"; // Outputs "1".
54// llvm::outs() << isa<MyDerivedClass2>(B) << "\n"; // Outputs "0'.
55// }
56//
57// @endcode
58//
59//===----------------------------------------------------------------------===//
60
61#ifndef LLVM_SUPPORT_EXTENSIBLERTTI_H
62#define LLVM_SUPPORT_EXTENSIBLERTTI_H
63
64namespace llvm {
65
66template <typename ThisT, typename ParentT> class RTTIExtends;
67
68/// Base class for the extensible RTTI hierarchy.
69///
70/// This class defines virtual methods, dynamicClassID and isA, that enable
71/// type comparisons.
72class RTTIRoot {
73public:
74 virtual ~RTTIRoot() = default;
75
76 /// Returns the class ID for this type.
77 static const void *classID() { return &ID; }
78
79 /// Returns the class ID for the dynamic type of this RTTIRoot instance.
80 virtual const void *dynamicClassID() const = 0;
81
82 /// Returns true if this class's ID matches the given class ID.
83 virtual bool isA(const void *const ClassID) const {
84 return ClassID == classID();
85 }
86
87 /// Check whether this instance is a subclass of QueryT.
88 template <typename QueryT>
89 bool isA() const { return isA(QueryT::classID()); }
90
91private:
92 virtual void anchor();
93
94 static char ID;
95};
96
97/// Inheritance utility for extensible RTTI.
98///
99/// Supports single inheritance only: A class can only have one
100/// ExtensibleRTTI-parent (i.e. a parent for which the isa<> test will work),
101/// though it can have many non-ExtensibleRTTI parents.
102///
103/// RTTIExtents uses CRTP so the first template argument to RTTIExtends is the
104/// newly introduced type, and the *second* argument is the parent class.
105///
106/// class MyType : public RTTIExtends<MyType, RTTIRoot> {
107/// public:
108/// static char ID;
109/// };
110///
111/// class MyDerivedType : public RTTIExtends<MyDerivedType, MyType> {
112/// public:
113/// static char ID;
114/// };
115///
116template <typename ThisT, typename ParentT>
117class RTTIExtends : public ParentT {
118public:
119 // Inherit constructors from ParentT.
120 using ParentT::ParentT;
121
122 static const void *classID() { return &ThisT::ID; }
123
124 const void *dynamicClassID() const override { return &ThisT::ID; }
125
126 bool isA(const void *const ClassID) const override {
127 return ClassID == classID() || ParentT::isA(ClassID);
128 }
129
130 static bool classof(const RTTIRoot *R) { return R->isA<ThisT>(); }
131};
132
133} // end namespace llvm
134
135#endif // LLVM_SUPPORT_EXTENSIBLERTTI_H
136