Index: Support/ExtensibleRTTI.cpp =================================================================== --- /dev/null +++ Support/ExtensibleRTTI.cpp @@ -0,0 +1,13 @@ +//===----- lib/Support/ExtensibleRTTI.cpp - ExtensibleRTTI utilities ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/ExtensibleRTTI.h" + +void llvm::RTTIRoot::anchor() {} +char llvm::RTTIRoot::ID = 0; Index: Support/ExtensibleRTTITest.cpp =================================================================== --- /dev/null +++ Support/ExtensibleRTTITest.cpp @@ -0,0 +1,86 @@ +//===------ unittests/ExtensibleRTTITest.cpp - Extensible RTTI Tests ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Casting.h" +#include "llvm/Support/ExtensibleRTTI.h" + +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +class MyBaseType : public RTTIExtends { +public: + static char ID; +}; + +class MyDerivedType : public RTTIExtends { +public: + static char ID; +}; + +class MyOtherDerivedType : public RTTIExtends { +public: + static char ID; +}; + +class MyDeeperDerivedType + : public RTTIExtends { +public: + static char ID; +}; + +char MyBaseType::ID = 0; +char MyDerivedType::ID = 0; +char MyOtherDerivedType::ID = 0; +char MyDeeperDerivedType::ID = 0; + +TEST(ExtensibleRTTI, isa) { + MyBaseType B; + MyDerivedType D; + MyDeeperDerivedType DD; + + EXPECT_TRUE(isa(B)); + EXPECT_FALSE(isa(B)); + EXPECT_FALSE(isa(B)); + EXPECT_FALSE(isa(B)); + + EXPECT_TRUE(isa(D)); + EXPECT_TRUE(isa(D)); + EXPECT_FALSE(isa(D)); + EXPECT_FALSE(isa(D)); + + EXPECT_TRUE(isa(DD)); + EXPECT_TRUE(isa(DD)); + EXPECT_FALSE(isa(DD)); + EXPECT_TRUE(isa(DD)); +} + +TEST(ExtensibleRTTI, cast) { + MyDerivedType D; + MyBaseType &BD = D; + + cast(D); + cast(BD); + cast(BD); +} + +TEST(ExtensibleRTTI, dyn_cast) { + MyBaseType B; + MyDerivedType D; + MyBaseType &BD = D; + + EXPECT_EQ(dyn_cast(&B), nullptr); + EXPECT_EQ(dyn_cast(&D), &D); + EXPECT_EQ(dyn_cast(&BD), &BD); + EXPECT_EQ(dyn_cast(&BD), &D); +} + +} // end anon namespace Index: llvm/Support/ExtensibleRTTI.h =================================================================== --- /dev/null +++ llvm/Support/ExtensibleRTTI.h @@ -0,0 +1,90 @@ +//===-- llvm/Support/ExtensibleRTTI.h - ExtensibleRTTI support --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Extensible RTTI mechanism designed to work with Casting.h. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_EXTENSIBLERTTI_H +#define LLVM_SUPPORT_EXTENSIBLERTTI_H + +namespace llvm { + +template +class RTTIExtends; + +/// Base class for error info classes. Do not extend this directly: Extend +/// the RTTIExtends template subclass instead. +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; + + 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. +/// +/// One quirk: 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: + + 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