diff --git a/llvm/include/llvm/Support/ExtensibleRTTI.h b/llvm/include/llvm/Support/ExtensibleRTTI.h index d3193be6f529e..e11e3bd06e93c 100644 --- a/llvm/include/llvm/Support/ExtensibleRTTI.h +++ b/llvm/include/llvm/Support/ExtensibleRTTI.h @@ -81,10 +81,6 @@ class RTTIRoot { return ClassID == classID(); } - /// Check whether this instance is a subclass of QueryT. - template - bool isA() const { return isA(QueryT::classID()); } - private: virtual void anchor(); @@ -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 { /// public: /// static char ID; @@ -110,21 +108,41 @@ class RTTIRoot { /// static char ID; /// }; /// -template -class RTTIExtends : public ParentT { +/// class MyOtherType : public RTTIExtends { +/// public: +/// static char ID; +/// }; +/// +/// class MyMultipleInheritanceType +/// : public RTTIExtends { +/// public: +/// static char ID; +/// }; +/// +/// @endcode +/// +template +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 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(); } + template static bool classof(const T *R) { + return R->template isA(); + } }; } // end namespace llvm diff --git a/llvm/unittests/Support/ExtensibleRTTITest.cpp b/llvm/unittests/Support/ExtensibleRTTITest.cpp index 9715d26a9de29..8b0ff89745b20 100644 --- a/llvm/unittests/Support/ExtensibleRTTITest.cpp +++ b/llvm/unittests/Support/ExtensibleRTTITest.cpp @@ -36,15 +36,42 @@ class MyDeeperDerivedType static char ID; }; +class MyMultipleInheritanceType + : public RTTIExtends { +public: + static char ID; +}; + +class MyTypeWithConstructor + : public RTTIExtends { +public: + static char ID; + + MyTypeWithConstructor(int) {} +}; + +class MyDerivedTypeWithConstructor + : public RTTIExtends { +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(B)); EXPECT_FALSE(isa(B)); @@ -60,26 +87,57 @@ TEST(ExtensibleRTTI, isa) { EXPECT_TRUE(isa(DD)); EXPECT_FALSE(isa(DD)); EXPECT_TRUE(isa(DD)); + + EXPECT_TRUE(isa(MI)); + EXPECT_TRUE(isa(MI)); + EXPECT_TRUE(isa(MI)); + EXPECT_FALSE(isa(MI)); + EXPECT_TRUE(isa(MI)); } TEST(ExtensibleRTTI, cast) { - MyDerivedType D; - MyBaseType &BD = D; - - (void)cast(D); - (void)cast(BD); - (void)cast(BD); + MyMultipleInheritanceType MI; + MyDerivedType &D = MI; + MyOtherDerivedType &OD = MI; + MyBaseType &B = D; + + EXPECT_EQ(&cast(D), &B); + EXPECT_EQ(&cast(MI), &D); + EXPECT_EQ(&cast(MI), &OD); + EXPECT_EQ(&cast(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(&B), nullptr); - EXPECT_EQ(dyn_cast(&D), &D); EXPECT_EQ(dyn_cast(&BD), &BD); EXPECT_EQ(dyn_cast(&BD), &D); + + EXPECT_EQ(dyn_cast(&BOD), &BOD); + EXPECT_EQ(dyn_cast(&BOD), &OD); + + EXPECT_EQ(dyn_cast(&D), &BD); + EXPECT_EQ(dyn_cast(&D), &D); + EXPECT_EQ(dyn_cast(&D), &MI); + + EXPECT_EQ(dyn_cast(&OD), &BOD); + EXPECT_EQ(dyn_cast(&OD), &OD); + EXPECT_EQ(dyn_cast(&OD), &MI); + + EXPECT_EQ(dyn_cast(&MI), &D); + EXPECT_EQ(dyn_cast(&MI), &MI); + + EXPECT_EQ(dyn_cast(&MI), &D); + EXPECT_EQ(dyn_cast(&MI), &OD); + EXPECT_EQ(dyn_cast(&MI), &MI); +} + +TEST(ExtensibleRTTI, multiple_inheritance_constructor) { + MyDerivedTypeWithConstructor V(42); } } // namespace