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