#. For each class in the hierarchy that has children, implement a
``classof`` that checks a range of the first child's ``Kind`` and the
last child's ``Kind``.
+
+RTTI for Open Class Hierarchies
+===============================
+
+Sometimes it is not possible to know all types in a hierarchy ahead of time.
+For example, in the shapes hierarchy described above the authors may have
+wanted their code to work for user defined shapes too. To support use cases
+that require open hierarchies LLVM provides the ``RTTIRoot`` and
+``RTTIExtends`` utilities.
+
+The ``RTTIRoot`` class describes an interface for performing RTTI checks. The
+``RTTIExtends`` class template provides an implementation of this interface
+for classes derived from ``RTTIRoot``. ``RTTIExtends`` uses the "`Curiously
+Recurring Template Idiom`_", taking the class being defined as its first
+template argument and the parent class as the second argument. Any class that
+uses ``RTTIExtends`` must define a ``static char ID`` member, the address of
+which will be used to identify the type.
+
+This open-hierarchy RTTI support should only be used if your use case requries
+it. Otherwise the standard LLVM RTTI system should be preferred.
+
+.. _`Curiously Recurring Template Idiom`:
+https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
+
+E.g.
+
+.. code-block:: c++
+
+ class Shape : public RTTIExtends<Shape, RTTIRoot> {
+ public:
+ static char ID;
+ virtual double computeArea() = 0;
+ };
+
+ class Square : public RTTIExtends<Square, Shape> {
+ double SideLength;
+ public:
+ static char ID;
+
+ Square(double S) : SideLength(S) {}
+ double computeArea() override;
+ };
+
+ class Circle : public RTTIExtends<Circle, Shape> {
+ double Radius;
+ public:
+ static char ID;
+
+ Circle(double R) : Radius(R) {}
+ double computeArea() override;
+ };
+
+ char Shape::ID = 0;
+ char Square::ID = 0;
+ char Circle::ID = 0;
--- /dev/null
+//===-- 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// \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<MyBaseClass, RTTIRoot> {
+// public:
+// static char ID;
+// virtual void foo() = 0;
+// };
+//
+// class MyDerivedClass1 : public RTTIExtends<MyDerivedClass1, MyBaseClass> {
+// public:
+// static char ID;
+// void foo() override {}
+// };
+//
+// class MyDerivedClass2 : public RTTIExtends<MyDerivedClass2, MyBaseClass> {
+// public:
+// static char ID;
+// void foo() override {}
+// };
+//
+// char MyBaseClass::ID = 0;
+// char MyDerivedClass1::ID = 0;
+// char MyDerivedClass2:: ID = 0;
+//
+// void fn() {
+// std::unique_ptr<MyBaseClass> B = llvm::make_unique<MyDerivedClass1>();
+// llvm::outs() << isa<MyBaseClass>(B) << "\n"; // Outputs "1".
+// llvm::outs() << isa<MyDerivedClass1>(B) << "\n"; // Outputs "1".
+// llvm::outs() << isa<MyDerivedClass2>(B) << "\n"; // Outputs "0'.
+// }
+//
+// @endcode
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_EXTENSIBLERTTI_H
+#define LLVM_SUPPORT_EXTENSIBLERTTI_H
+
+namespace llvm {
+
+template <typename ThisT, typename ParentT> class RTTIExtends;
+
+/// 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 <typename QueryT>
+ 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<MyType, RTTIRoot> {
+/// public:
+/// static char ID;
+/// };
+///
+/// class MyDerivedType : public RTTIExtends<MyDerivedType, MyType> {
+/// public:
+/// static char ID;
+/// };
+///
+template <typename ThisT, typename ParentT>
+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<ThisT>(); }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_EXTENSIBLERTTI_H
ELFAttributes.cpp
Error.cpp
ErrorHandling.cpp
+ ExtensibleRTTI.cpp
FileCheck.cpp
FileCollector.cpp
FileUtilities.cpp
ErrnoTest.cpp
ErrorOrTest.cpp
ErrorTest.cpp
+ ExtensibleRTTITest.cpp
FileCheckTest.cpp
FileCollectorTest.cpp
FileOutputBufferTest.cpp
--- /dev/null
+//===------ 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/ExtensibleRTTI.h"
+#include "llvm/Support/Casting.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+class MyBaseType : public RTTIExtends<MyBaseType, RTTIRoot> {
+public:
+ static char ID;
+};
+
+class MyDerivedType : public RTTIExtends<MyDerivedType, MyBaseType> {
+public:
+ static char ID;
+};
+
+class MyOtherDerivedType : public RTTIExtends<MyOtherDerivedType, MyBaseType> {
+public:
+ static char ID;
+};
+
+class MyDeeperDerivedType
+ : public RTTIExtends<MyDeeperDerivedType, MyDerivedType> {
+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<MyBaseType>(B));
+ EXPECT_FALSE(isa<MyDerivedType>(B));
+ EXPECT_FALSE(isa<MyOtherDerivedType>(B));
+ EXPECT_FALSE(isa<MyDeeperDerivedType>(B));
+
+ EXPECT_TRUE(isa<MyBaseType>(D));
+ EXPECT_TRUE(isa<MyDerivedType>(D));
+ EXPECT_FALSE(isa<MyOtherDerivedType>(D));
+ EXPECT_FALSE(isa<MyDeeperDerivedType>(D));
+
+ EXPECT_TRUE(isa<MyBaseType>(DD));
+ EXPECT_TRUE(isa<MyDerivedType>(DD));
+ EXPECT_FALSE(isa<MyOtherDerivedType>(DD));
+ EXPECT_TRUE(isa<MyDeeperDerivedType>(DD));
+}
+
+TEST(ExtensibleRTTI, cast) {
+ MyDerivedType D;
+ MyBaseType &BD = D;
+
+ cast<MyBaseType>(D);
+ cast<MyBaseType>(BD);
+ cast<MyDerivedType>(BD);
+}
+
+TEST(ExtensibleRTTI, dyn_cast) {
+ MyBaseType B;
+ MyDerivedType D;
+ MyBaseType &BD = D;
+
+ EXPECT_EQ(dyn_cast<MyDerivedType>(&B), nullptr);
+ EXPECT_EQ(dyn_cast<MyDerivedType>(&D), &D);
+ EXPECT_EQ(dyn_cast<MyBaseType>(&BD), &BD);
+ EXPECT_EQ(dyn_cast<MyDerivedType>(&BD), &D);
+}
+
+} // namespace