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 namespace llvm { 64 65 /// Base class for the extensible RTTI hierarchy. 66 /// 67 /// This class defines virtual methods, dynamicClassID and isA, that enable 68 /// type comparisons. 69 class RTTIRoot { 70 public: 71 virtual ~RTTIRoot() = default; 72 73 /// Returns the class ID for this type. classID()74 static const void *classID() { return &ID; } 75 76 /// Returns the class ID for the dynamic type of this RTTIRoot instance. 77 virtual const void *dynamicClassID() const = 0; 78 79 /// Returns true if this class's ID matches the given class ID. isA(const void * const ClassID)80 virtual bool isA(const void *const ClassID) const { 81 return ClassID == classID(); 82 } 83 84 /// Check whether this instance is a subclass of QueryT. 85 template <typename QueryT> isA()86 bool isA() const { return isA(QueryT::classID()); } 87 88 private: 89 virtual void anchor(); 90 91 static char ID; 92 }; 93 94 /// Inheritance utility for extensible RTTI. 95 /// 96 /// Supports single inheritance only: A class can only have one 97 /// ExtensibleRTTI-parent (i.e. a parent for which the isa<> test will work), 98 /// though it can have many non-ExtensibleRTTI parents. 99 /// 100 /// RTTIExtents uses CRTP so the first template argument to RTTIExtends is the 101 /// newly introduced type, and the *second* argument is the parent class. 102 /// 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 template <typename ThisT, typename ParentT> 114 class RTTIExtends : public ParentT { 115 public: 116 // Inherit constructors from ParentT. 117 using ParentT::ParentT; 118 classID()119 static const void *classID() { return &ThisT::ID; } 120 dynamicClassID()121 const void *dynamicClassID() const override { return &ThisT::ID; } 122 isA(const void * const ClassID)123 bool isA(const void *const ClassID) const override { 124 return ClassID == classID() || ParentT::isA(ClassID); 125 } 126 classof(const RTTIRoot * R)127 static bool classof(const RTTIRoot *R) { return R->isA<ThisT>(); } 128 }; 129 130 } // end namespace llvm 131 132 #endif // LLVM_SUPPORT_EXTENSIBLERTTI_H 133