Skip to content

Commit 9039b59

Browse files
committed
[orc-rt] Add rtti header and unit tests.
The orc-rt extensible RTTI mechanism is used to provide simple dynamic RTTI checks for orc-rt types that do not depend on standard C++ RTTI (meaning that they will work equally well for programs compiled with -fno-rtti).
1 parent ca0a8d9 commit 9039b59

File tree

6 files changed

+217
-0
lines changed

6 files changed

+217
-0
lines changed

orc-rt/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ set(ORC_RT_HEADERS
22
orc-rt-c/orc-rt.h
33
orc-rt/bitmask-enum.h
44
orc-rt/math.h
5+
orc-rt/rtti.h
56
orc-rt/span.h
67
)
78

orc-rt/include/orc-rt/rtti.h

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
//===------------- rtti.h - RTTI support for ORC RT -------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// \file
10+
//
11+
// Provides an extensible RTTI mechanism, that can be used regardless of whether
12+
// the runtime is built with -frtti or not. This is predominantly used to
13+
// support error handling.
14+
//
15+
// The RTTIRoot class defines methods for comparing type ids. Implementations
16+
// of these methods can be injected into new classes using the RTTIExtends
17+
// class template.
18+
//
19+
// E.g.
20+
//
21+
// @code{.cpp}
22+
// class MyBaseClass : public RTTIExtends<MyBaseClass, RTTIRoot> {
23+
// public:
24+
// virtual void foo() = 0;
25+
// };
26+
//
27+
// class MyDerivedClass1 : public RTTIExtends<MyDerivedClass1, MyBaseClass> {
28+
// public:
29+
// void foo() override {}
30+
// };
31+
//
32+
// class MyDerivedClass2 : public RTTIExtends<MyDerivedClass2, MyBaseClass> {
33+
// public:
34+
// void foo() override {}
35+
// };
36+
//
37+
// void fn() {
38+
// std::unique_ptr<MyBaseClass> B = std::make_unique<MyDerivedClass1>();
39+
// outs() << isa<MyBaseClass>(B) << "\n"; // Outputs "1".
40+
// outs() << isa<MyDerivedClass1>(B) << "\n"; // Outputs "1".
41+
// outs() << isa<MyDerivedClass2>(B) << "\n"; // Outputs "0'.
42+
// }
43+
//
44+
// @endcode
45+
//
46+
// Note:
47+
// This header was adapted from llvm/Support/ExtensibleRTTI.h, however the
48+
// data structures are not shared and the code need not be kept in sync.
49+
//
50+
//===----------------------------------------------------------------------===//
51+
52+
#ifndef ORC_RT_RTTI_H
53+
#define ORC_RT_RTTI_H
54+
55+
namespace orc_rt {
56+
57+
template <typename ThisT, typename ParentT> class RTTIExtends;
58+
59+
/// Base class for the extensible RTTI hierarchy.
60+
///
61+
/// This class defines virtual methods, dynamicClassID and isA, that enable
62+
/// type comparisons.
63+
class RTTIRoot {
64+
public:
65+
virtual ~RTTIRoot() = default;
66+
67+
/// Returns the class ID for this type.
68+
static const void *classID() noexcept { return &ID; }
69+
70+
/// Returns the class ID for the dynamic type of this RTTIRoot instance.
71+
virtual const void *dynamicClassID() const noexcept = 0;
72+
73+
/// Returns true if this class's ID matches the given class ID.
74+
virtual bool isA(const void *const ClassID) const noexcept {
75+
return ClassID == classID();
76+
}
77+
78+
/// Check whether this instance is a subclass of QueryT.
79+
template <typename QueryT> bool isA() const noexcept {
80+
return isA(QueryT::classID());
81+
}
82+
83+
static bool classof(const RTTIRoot *R) noexcept { return R->isA<RTTIRoot>(); }
84+
85+
private:
86+
virtual void anchor();
87+
88+
static char ID;
89+
};
90+
91+
/// Inheritance utility for extensible RTTI.
92+
///
93+
/// Supports single inheritance only: A class can only have one
94+
/// ExtensibleRTTI-parent (i.e. a parent for which the isa<> test will work),
95+
/// though it can have many non-ExtensibleRTTI parents.
96+
///
97+
/// RTTIExtents uses CRTP so the first template argument to RTTIExtends is the
98+
/// newly introduced type, and the *second* argument is the parent class.
99+
///
100+
/// class MyType : public RTTIExtends<MyType, RTTIRoot> {
101+
/// ...
102+
/// };
103+
///
104+
/// class MyDerivedType : public RTTIExtends<MyDerivedType, MyType> {
105+
/// ...
106+
/// };
107+
///
108+
template <typename ThisT, typename ParentT> class RTTIExtends : public ParentT {
109+
public:
110+
// Inherit constructors and isA methods from ParentT.
111+
using ParentT::isA;
112+
using ParentT::ParentT;
113+
114+
static char ID;
115+
116+
static const void *classID() noexcept { return &ThisT::ID; }
117+
118+
const void *dynamicClassID() const noexcept override { return &ThisT::ID; }
119+
120+
bool isA(const void *const ClassID) const noexcept override {
121+
return ClassID == classID() || ParentT::isA(ClassID);
122+
}
123+
124+
static bool classof(const RTTIRoot *R) { return R->isA<ThisT>(); }
125+
};
126+
127+
template <typename ThisT, typename ParentT>
128+
char RTTIExtends<ThisT, ParentT>::ID = 0;
129+
130+
/// Returns true if the given value is an instance of the template type
131+
/// parameter.
132+
template <typename To, typename From> bool isa(const From &Value) noexcept {
133+
return To::classof(&Value);
134+
}
135+
136+
} // namespace orc_rt
137+
138+
#endif // ORC_RT_RTTI_H

orc-rt/lib/executor/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
set(files
22
orc-rt-executor.cpp
3+
rtti.cpp
34
)
45

56
add_library(orc-rt-executor STATIC ${files})

orc-rt/lib/executor/rtti.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//===- rtti.cpp -----------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file is a part of the ORC runtime support library.
10+
//
11+
// Note:
12+
// This source file was adapted from lib/Support/ExtensibleRTTI.cpp, however
13+
// the data structures are not shared and the code need not be kept in sync.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#include "orc-rt/rtti.h"
18+
19+
namespace orc_rt {
20+
21+
char RTTIRoot::ID = 0;
22+
void RTTIRoot::anchor() {}
23+
24+
} // namespace orc_rt

orc-rt/unittests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ endfunction()
1414
add_orc_rt_unittest(CoreTests
1515
bitmask-enum-test.cpp
1616
math-test.cpp
17+
rtti-test.cpp
1718
span-test.cpp
1819
DISABLE_LLVM_LINK_LLVM_DYLIB
1920
)

orc-rt/unittests/rtti-test.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//===-- rtti_test.cpp -----------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Note:
10+
// This unit test was adapted from
11+
// llvm/unittests/Support/ExtensibleRTTITest.cpp
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#include "orc-rt/rtti.h"
16+
#include "gtest/gtest.h"
17+
18+
using namespace orc_rt;
19+
20+
namespace {
21+
22+
class MyBase : public RTTIExtends<MyBase, RTTIRoot> {};
23+
24+
class MyDerivedA : public RTTIExtends<MyDerivedA, MyBase> {};
25+
26+
class MyDerivedB : public RTTIExtends<MyDerivedB, MyBase> {};
27+
28+
} // end anonymous namespace
29+
30+
TEST(ExtensibleRTTITest, BaseCheck) {
31+
MyBase MB;
32+
MyDerivedA MDA;
33+
MyDerivedB MDB;
34+
35+
// Check MB properties.
36+
EXPECT_TRUE(isa<RTTIRoot>(MB));
37+
EXPECT_TRUE(isa<MyBase>(MB));
38+
EXPECT_FALSE(isa<MyDerivedA>(MB));
39+
EXPECT_FALSE(isa<MyDerivedB>(MB));
40+
41+
// Check MDA properties.
42+
EXPECT_TRUE(isa<RTTIRoot>(MDA));
43+
EXPECT_TRUE(isa<MyBase>(MDA));
44+
EXPECT_TRUE(isa<MyDerivedA>(MDA));
45+
EXPECT_FALSE(isa<MyDerivedB>(MDA));
46+
47+
// Check MDB properties.
48+
EXPECT_TRUE(isa<RTTIRoot>(MDB));
49+
EXPECT_TRUE(isa<MyBase>(MDB));
50+
EXPECT_FALSE(isa<MyDerivedA>(MDB));
51+
EXPECT_TRUE(isa<MyDerivedB>(MDB));
52+
}

0 commit comments

Comments
 (0)