Skip to content

Commit 633a6c9

Browse files
authored
[Support] Extend ExtensibleRTTI utility to support basic multiple inheritance. (#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.
1 parent 7b9f988 commit 633a6c9

File tree

2 files changed

+99
-23
lines changed

2 files changed

+99
-23
lines changed

llvm/include/llvm/Support/ExtensibleRTTI.h

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,6 @@ class RTTIRoot {
8181
return ClassID == classID();
8282
}
8383

84-
/// Check whether this instance is a subclass of QueryT.
85-
template <typename QueryT>
86-
bool isA() const { return isA(QueryT::classID()); }
87-
8884
private:
8985
virtual void anchor();
9086

@@ -93,13 +89,15 @@ class RTTIRoot {
9389

9490
/// Inheritance utility for extensible RTTI.
9591
///
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.
92+
/// Multiple inheritance is supported, but RTTIExtends only inherits
93+
/// constructors from the first base class. All subsequent bases will be
94+
/// default constructed. Virtual and non-public inheritance are not supported.
9995
///
10096
/// RTTIExtents uses CRTP so the first template argument to RTTIExtends is the
101-
/// newly introduced type, and the *second* argument is the parent class.
97+
/// newly introduced type, and the *second and later* arguments are the parent
98+
/// classes.
10299
///
100+
/// @code{.cpp}
103101
/// class MyType : public RTTIExtends<MyType, RTTIRoot> {
104102
/// public:
105103
/// static char ID;
@@ -110,21 +108,41 @@ class RTTIRoot {
110108
/// static char ID;
111109
/// };
112110
///
113-
template <typename ThisT, typename ParentT>
114-
class RTTIExtends : public ParentT {
111+
/// class MyOtherType : public RTTIExtends<MyOtherType, MyType> {
112+
/// public:
113+
/// static char ID;
114+
/// };
115+
///
116+
/// class MyMultipleInheritanceType
117+
/// : public RTTIExtends<MyMultipleInheritanceType,
118+
/// MyDerivedType, MyOtherType> {
119+
/// public:
120+
/// static char ID;
121+
/// };
122+
///
123+
/// @endcode
124+
///
125+
template <typename ThisT, typename ParentT, typename... ParentTs>
126+
class RTTIExtends : public ParentT, public ParentTs... {
115127
public:
116-
// Inherit constructors from ParentT.
128+
// Inherit constructors from the first Parent.
117129
using ParentT::ParentT;
118130

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

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

135+
/// Check whether this instance is a subclass of QueryT.
136+
template <typename QueryT> bool isA() const { return isA(QueryT::classID()); }
137+
123138
bool isA(const void *const ClassID) const override {
124-
return ClassID == classID() || ParentT::isA(ClassID);
139+
return ClassID == classID() || ParentT::isA(ClassID) ||
140+
(ParentTs::isA(ClassID) || ...);
125141
}
126142

127-
static bool classof(const RTTIRoot *R) { return R->isA<ThisT>(); }
143+
template <typename T> static bool classof(const T *R) {
144+
return R->template isA<ThisT>();
145+
}
128146
};
129147

130148
} // end namespace llvm

llvm/unittests/Support/ExtensibleRTTITest.cpp

Lines changed: 68 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,42 @@ class MyDeeperDerivedType
3636
static char ID;
3737
};
3838

39+
class MyMultipleInheritanceType
40+
: public RTTIExtends<MyMultipleInheritanceType, MyDerivedType,
41+
MyOtherDerivedType> {
42+
public:
43+
static char ID;
44+
};
45+
46+
class MyTypeWithConstructor
47+
: public RTTIExtends<MyTypeWithConstructor, MyBaseType> {
48+
public:
49+
static char ID;
50+
51+
MyTypeWithConstructor(int) {}
52+
};
53+
54+
class MyDerivedTypeWithConstructor
55+
: public RTTIExtends<MyDerivedTypeWithConstructor, MyTypeWithConstructor> {
56+
public:
57+
static char ID;
58+
59+
MyDerivedTypeWithConstructor(int x) : RTTIExtends(x) {}
60+
};
61+
3962
char MyBaseType::ID = 0;
4063
char MyDerivedType::ID = 0;
4164
char MyOtherDerivedType::ID = 0;
4265
char MyDeeperDerivedType::ID = 0;
66+
char MyMultipleInheritanceType::ID = 0;
67+
char MyTypeWithConstructor::ID = 0;
68+
char MyDerivedTypeWithConstructor::ID = 0;
4369

4470
TEST(ExtensibleRTTI, isa) {
4571
MyBaseType B;
4672
MyDerivedType D;
4773
MyDeeperDerivedType DD;
74+
MyMultipleInheritanceType MI;
4875

4976
EXPECT_TRUE(isa<MyBaseType>(B));
5077
EXPECT_FALSE(isa<MyDerivedType>(B));
@@ -60,26 +87,57 @@ TEST(ExtensibleRTTI, isa) {
6087
EXPECT_TRUE(isa<MyDerivedType>(DD));
6188
EXPECT_FALSE(isa<MyOtherDerivedType>(DD));
6289
EXPECT_TRUE(isa<MyDeeperDerivedType>(DD));
90+
91+
EXPECT_TRUE(isa<MyBaseType>(MI));
92+
EXPECT_TRUE(isa<MyDerivedType>(MI));
93+
EXPECT_TRUE(isa<MyOtherDerivedType>(MI));
94+
EXPECT_FALSE(isa<MyDeeperDerivedType>(MI));
95+
EXPECT_TRUE(isa<MyMultipleInheritanceType>(MI));
6396
}
6497

6598
TEST(ExtensibleRTTI, cast) {
66-
MyDerivedType D;
67-
MyBaseType &BD = D;
68-
69-
(void)cast<MyBaseType>(D);
70-
(void)cast<MyBaseType>(BD);
71-
(void)cast<MyDerivedType>(BD);
99+
MyMultipleInheritanceType MI;
100+
MyDerivedType &D = MI;
101+
MyOtherDerivedType &OD = MI;
102+
MyBaseType &B = D;
103+
104+
EXPECT_EQ(&cast<MyBaseType>(D), &B);
105+
EXPECT_EQ(&cast<MyDerivedType>(MI), &D);
106+
EXPECT_EQ(&cast<MyOtherDerivedType>(MI), &OD);
107+
EXPECT_EQ(&cast<MyMultipleInheritanceType>(MI), &MI);
72108
}
73109

74110
TEST(ExtensibleRTTI, dyn_cast) {
75-
MyBaseType B;
76-
MyDerivedType D;
111+
MyMultipleInheritanceType MI;
112+
MyDerivedType &D = MI;
113+
MyOtherDerivedType &OD = MI;
77114
MyBaseType &BD = D;
115+
MyBaseType &BOD = OD;
78116

79-
EXPECT_EQ(dyn_cast<MyDerivedType>(&B), nullptr);
80-
EXPECT_EQ(dyn_cast<MyDerivedType>(&D), &D);
81117
EXPECT_EQ(dyn_cast<MyBaseType>(&BD), &BD);
82118
EXPECT_EQ(dyn_cast<MyDerivedType>(&BD), &D);
119+
120+
EXPECT_EQ(dyn_cast<MyBaseType>(&BOD), &BOD);
121+
EXPECT_EQ(dyn_cast<MyOtherDerivedType>(&BOD), &OD);
122+
123+
EXPECT_EQ(dyn_cast<MyBaseType>(&D), &BD);
124+
EXPECT_EQ(dyn_cast<MyDerivedType>(&D), &D);
125+
EXPECT_EQ(dyn_cast<MyMultipleInheritanceType>(&D), &MI);
126+
127+
EXPECT_EQ(dyn_cast<MyBaseType>(&OD), &BOD);
128+
EXPECT_EQ(dyn_cast<MyOtherDerivedType>(&OD), &OD);
129+
EXPECT_EQ(dyn_cast<MyMultipleInheritanceType>(&OD), &MI);
130+
131+
EXPECT_EQ(dyn_cast<MyDerivedType>(&MI), &D);
132+
EXPECT_EQ(dyn_cast<MyMultipleInheritanceType>(&MI), &MI);
133+
134+
EXPECT_EQ(dyn_cast<MyDerivedType>(&MI), &D);
135+
EXPECT_EQ(dyn_cast<MyOtherDerivedType>(&MI), &OD);
136+
EXPECT_EQ(dyn_cast<MyMultipleInheritanceType>(&MI), &MI);
137+
}
138+
139+
TEST(ExtensibleRTTI, multiple_inheritance_constructor) {
140+
MyDerivedTypeWithConstructor V(42);
83141
}
84142

85143
} // namespace

0 commit comments

Comments
 (0)