//===-- llvm/Support/ExtensibleRTTI.h - ExtensibleRTTI support --*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // \file // // Defines an extensible RTTI mechanism designed to work with Casting.h. // // Extensible RTTI differs from LLVM's primary RTTI mechanism (see // llvm.org/docs/HowToSetUpLLVMStyleRTTI.html) by supporting open type // hierarchies, where new types can be added from outside libraries without // needing to change existing code. LLVM's primary RTTI mechanism should be // preferred where possible, but where open hierarchies are needed this system // can be used. // // The RTTIRoot class defines methods for comparing type ids. Implementations // of these methods can be injected into new classes using the RTTIExtends // class template. // // E.g. // // @code{.cpp} // class MyBaseClass : public RTTIExtends { // public: // static char ID; // virtual void foo() = 0; // }; // // class MyDerivedClass1 : public RTTIExtends { // public: // static char ID; // void foo() override {} // }; // // class MyDerivedClass2 : public RTTIExtends { // public: // static char ID; // void foo() override {} // }; // // char MyBaseClass::ID = 0; // char MyDerivedClass1::ID = 0; // char MyDerivedClass2:: ID = 0; // // void fn() { // std::unique_ptr B = llvm::make_unique(); // llvm::outs() << isa(B) << "\n"; // Outputs "1". // llvm::outs() << isa(B) << "\n"; // Outputs "1". // llvm::outs() << isa(B) << "\n"; // Outputs "0'. // } // // @endcode // //===----------------------------------------------------------------------===// #ifndef LLVM_SUPPORT_EXTENSIBLERTTI_H #define LLVM_SUPPORT_EXTENSIBLERTTI_H namespace llvm { /// Base class for the extensible RTTI hierarchy. /// /// This class defines virtual methods, dynamicClassID and isA, that enable /// type comparisons. class RTTIRoot { public: virtual ~RTTIRoot() = default; /// Returns the class ID for this type. static const void *classID() { return &ID; } /// Returns the class ID for the dynamic type of this RTTIRoot instance. virtual const void *dynamicClassID() const = 0; /// Returns true if this class's ID matches the given class ID. virtual bool isA(const void *const ClassID) const { return ClassID == classID(); } /// Check whether this instance is a subclass of QueryT. template bool isA() const { return isA(QueryT::classID()); } private: virtual void anchor(); static char ID; }; /// Inheritance utility for extensible RTTI. /// /// Supports single inheritance only: A class can only have one /// ExtensibleRTTI-parent (i.e. a parent for which the isa<> test will work), /// though it can have many non-ExtensibleRTTI parents. /// /// RTTIExtents uses CRTP so the first template argument to RTTIExtends is the /// newly introduced type, and the *second* argument is the parent class. /// /// class MyType : public RTTIExtends { /// public: /// static char ID; /// }; /// /// class MyDerivedType : public RTTIExtends { /// public: /// static char ID; /// }; /// template class RTTIExtends : public ParentT { public: // Inherit constructors from ParentT. using ParentT::ParentT; static const void *classID() { return &ThisT::ID; } const void *dynamicClassID() const override { return &ThisT::ID; } bool isA(const void *const ClassID) const override { return ClassID == classID() || ParentT::isA(ClassID); } static bool classof(const RTTIRoot *R) { return R->isA(); } }; } // end namespace llvm #endif // LLVM_SUPPORT_EXTENSIBLERTTI_H