Skip to content

Commit

Permalink
[Support] Extend ExtensibleRTTI utility to support basic multiple inh…
Browse files Browse the repository at this point in the history
…eritance. (#112643)

Clients can now pass multiple parent classes to RTTIExtends. Each parent
class will be inherited from publicly (and non-virtually). The isa,
cast, and dyn_cast methods will now work as expected for types with
multiple inheritance.
  • Loading branch information
lhames authored Oct 24, 2024
1 parent 7b9f988 commit 633a6c9
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 23 deletions.
44 changes: 31 additions & 13 deletions llvm/include/llvm/Support/ExtensibleRTTI.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,6 @@ class RTTIRoot {
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();

Expand All @@ -93,13 +89,15 @@ class RTTIRoot {

/// 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.
/// Multiple inheritance is supported, but RTTIExtends only inherits
/// constructors from the first base class. All subsequent bases will be
/// default constructed. Virtual and non-public inheritance are not supported.
///
/// RTTIExtents uses CRTP so the first template argument to RTTIExtends is the
/// newly introduced type, and the *second* argument is the parent class.
/// newly introduced type, and the *second and later* arguments are the parent
/// classes.
///
/// @code{.cpp}
/// class MyType : public RTTIExtends<MyType, RTTIRoot> {
/// public:
/// static char ID;
Expand All @@ -110,21 +108,41 @@ class RTTIRoot {
/// static char ID;
/// };
///
template <typename ThisT, typename ParentT>
class RTTIExtends : public ParentT {
/// class MyOtherType : public RTTIExtends<MyOtherType, MyType> {
/// public:
/// static char ID;
/// };
///
/// class MyMultipleInheritanceType
/// : public RTTIExtends<MyMultipleInheritanceType,
/// MyDerivedType, MyOtherType> {
/// public:
/// static char ID;
/// };
///
/// @endcode
///
template <typename ThisT, typename ParentT, typename... ParentTs>
class RTTIExtends : public ParentT, public ParentTs... {
public:
// Inherit constructors from ParentT.
// Inherit constructors from the first Parent.
using ParentT::ParentT;

static const void *classID() { return &ThisT::ID; }

const void *dynamicClassID() const override { return &ThisT::ID; }

/// Check whether this instance is a subclass of QueryT.
template <typename QueryT> bool isA() const { return isA(QueryT::classID()); }

bool isA(const void *const ClassID) const override {
return ClassID == classID() || ParentT::isA(ClassID);
return ClassID == classID() || ParentT::isA(ClassID) ||
(ParentTs::isA(ClassID) || ...);
}

static bool classof(const RTTIRoot *R) { return R->isA<ThisT>(); }
template <typename T> static bool classof(const T *R) {
return R->template isA<ThisT>();
}
};

} // end namespace llvm
Expand Down
78 changes: 68 additions & 10 deletions llvm/unittests/Support/ExtensibleRTTITest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,42 @@ class MyDeeperDerivedType
static char ID;
};

class MyMultipleInheritanceType
: public RTTIExtends<MyMultipleInheritanceType, MyDerivedType,
MyOtherDerivedType> {
public:
static char ID;
};

class MyTypeWithConstructor
: public RTTIExtends<MyTypeWithConstructor, MyBaseType> {
public:
static char ID;

MyTypeWithConstructor(int) {}
};

class MyDerivedTypeWithConstructor
: public RTTIExtends<MyDerivedTypeWithConstructor, MyTypeWithConstructor> {
public:
static char ID;

MyDerivedTypeWithConstructor(int x) : RTTIExtends(x) {}
};

char MyBaseType::ID = 0;
char MyDerivedType::ID = 0;
char MyOtherDerivedType::ID = 0;
char MyDeeperDerivedType::ID = 0;
char MyMultipleInheritanceType::ID = 0;
char MyTypeWithConstructor::ID = 0;
char MyDerivedTypeWithConstructor::ID = 0;

TEST(ExtensibleRTTI, isa) {
MyBaseType B;
MyDerivedType D;
MyDeeperDerivedType DD;
MyMultipleInheritanceType MI;

EXPECT_TRUE(isa<MyBaseType>(B));
EXPECT_FALSE(isa<MyDerivedType>(B));
Expand All @@ -60,26 +87,57 @@ TEST(ExtensibleRTTI, isa) {
EXPECT_TRUE(isa<MyDerivedType>(DD));
EXPECT_FALSE(isa<MyOtherDerivedType>(DD));
EXPECT_TRUE(isa<MyDeeperDerivedType>(DD));

EXPECT_TRUE(isa<MyBaseType>(MI));
EXPECT_TRUE(isa<MyDerivedType>(MI));
EXPECT_TRUE(isa<MyOtherDerivedType>(MI));
EXPECT_FALSE(isa<MyDeeperDerivedType>(MI));
EXPECT_TRUE(isa<MyMultipleInheritanceType>(MI));
}

TEST(ExtensibleRTTI, cast) {
MyDerivedType D;
MyBaseType &BD = D;

(void)cast<MyBaseType>(D);
(void)cast<MyBaseType>(BD);
(void)cast<MyDerivedType>(BD);
MyMultipleInheritanceType MI;
MyDerivedType &D = MI;
MyOtherDerivedType &OD = MI;
MyBaseType &B = D;

EXPECT_EQ(&cast<MyBaseType>(D), &B);
EXPECT_EQ(&cast<MyDerivedType>(MI), &D);
EXPECT_EQ(&cast<MyOtherDerivedType>(MI), &OD);
EXPECT_EQ(&cast<MyMultipleInheritanceType>(MI), &MI);
}

TEST(ExtensibleRTTI, dyn_cast) {
MyBaseType B;
MyDerivedType D;
MyMultipleInheritanceType MI;
MyDerivedType &D = MI;
MyOtherDerivedType &OD = MI;
MyBaseType &BD = D;
MyBaseType &BOD = OD;

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);

EXPECT_EQ(dyn_cast<MyBaseType>(&BOD), &BOD);
EXPECT_EQ(dyn_cast<MyOtherDerivedType>(&BOD), &OD);

EXPECT_EQ(dyn_cast<MyBaseType>(&D), &BD);
EXPECT_EQ(dyn_cast<MyDerivedType>(&D), &D);
EXPECT_EQ(dyn_cast<MyMultipleInheritanceType>(&D), &MI);

EXPECT_EQ(dyn_cast<MyBaseType>(&OD), &BOD);
EXPECT_EQ(dyn_cast<MyOtherDerivedType>(&OD), &OD);
EXPECT_EQ(dyn_cast<MyMultipleInheritanceType>(&OD), &MI);

EXPECT_EQ(dyn_cast<MyDerivedType>(&MI), &D);
EXPECT_EQ(dyn_cast<MyMultipleInheritanceType>(&MI), &MI);

EXPECT_EQ(dyn_cast<MyDerivedType>(&MI), &D);
EXPECT_EQ(dyn_cast<MyOtherDerivedType>(&MI), &OD);
EXPECT_EQ(dyn_cast<MyMultipleInheritanceType>(&MI), &MI);
}

TEST(ExtensibleRTTI, multiple_inheritance_constructor) {
MyDerivedTypeWithConstructor V(42);
}

} // namespace

0 comments on commit 633a6c9

Please sign in to comment.