mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-29 06:10:48 +00:00
Casting.h: Automatically handle isa<Base>(Derived).
Additionally, all such cases are handled with no dynamic check. All `classof()` of the form class Foo { [...] static bool classof(const Bar *) { return true; } [...] } where Foo is an ancestor of Bar are no longer necessary. Don't write them! Note: The exact test is `is_base_of<Foo, Bar>`, which is non-strict, so that Foo is considered an ancestor of itself. This leads to the following rule of thumb for LLVM-style RTTI: The argument type of `classof()` should be a strict ancestor. For more information about implementing LLVM-style RTTI, see docs/HowToSetUpLLVMStyleRTTI.rst llvm-svn: 165765
This commit is contained in:
parent
50f89739b9
commit
356281d8ad
@ -15,6 +15,7 @@
|
||||
#ifndef LLVM_SUPPORT_CASTING_H
|
||||
#define LLVM_SUPPORT_CASTING_H
|
||||
|
||||
#include "llvm/Support/type_traits.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
@ -44,13 +45,23 @@ template<typename From> struct simplify_type<const From> {
|
||||
// The core of the implementation of isa<X> is here; To and From should be
|
||||
// the names of classes. This template can be specialized to customize the
|
||||
// implementation of isa<> without rewriting it from scratch.
|
||||
template <typename To, typename From>
|
||||
template <typename To, typename From, typename Enabler = void>
|
||||
struct isa_impl {
|
||||
static inline bool doit(const From &Val) {
|
||||
return To::classof(&Val);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Always allow upcasts, and perform no dynamic check for them.
|
||||
template <typename To, typename From>
|
||||
struct isa_impl<To, From,
|
||||
typename llvm::enable_if_c<
|
||||
llvm::is_base_of<To, From>::value
|
||||
>::type
|
||||
> {
|
||||
static inline bool doit(const From &) { return true; }
|
||||
};
|
||||
|
||||
template <typename To, typename From> struct isa_impl_cl {
|
||||
static inline bool doit(const From &Val) {
|
||||
return isa_impl<To, From>::doit(Val);
|
||||
|
@ -153,3 +153,54 @@ const bar *B2 = &B;
|
||||
} // anonymous namespace
|
||||
|
||||
bar *llvm::fub() { return 0; }
|
||||
|
||||
namespace {
|
||||
namespace inferred_upcasting {
|
||||
// This test case verifies correct behavior of inferred upcasts when the
|
||||
// types are statically known to be OK to upcast. This is the case when,
|
||||
// for example, Derived inherits from Base, and we do `isa<Base>(Derived)`.
|
||||
|
||||
// Note: This test will actually fail to compile without inferred
|
||||
// upcasting.
|
||||
|
||||
class Base {
|
||||
public:
|
||||
// No classof. We are testing that the upcast is inferred.
|
||||
Base() {}
|
||||
};
|
||||
|
||||
class Derived : public Base {
|
||||
public:
|
||||
Derived() {}
|
||||
};
|
||||
|
||||
// Even with no explicit classof() in Base, we should still be able to cast
|
||||
// Derived to its base class.
|
||||
TEST(CastingTest, UpcastIsInferred) {
|
||||
Derived D;
|
||||
EXPECT_TRUE(isa<Base>(D));
|
||||
Base *BP = dyn_cast<Base>(&D);
|
||||
EXPECT_TRUE(BP != NULL);
|
||||
}
|
||||
|
||||
|
||||
// This test verifies that the inferred upcast takes precedence over an
|
||||
// explicitly written one. This is important because it verifies that the
|
||||
// dynamic check gets optimized away.
|
||||
class UseInferredUpcast {
|
||||
public:
|
||||
int Dummy;
|
||||
static bool classof(const UseInferredUpcast *) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(CastingTest, InferredUpcastTakesPrecedence) {
|
||||
UseInferredUpcast UIU;
|
||||
// Since the explicit classof() returns false, this will fail if the
|
||||
// explicit one is used.
|
||||
EXPECT_TRUE(isa<UseInferredUpcast>(&UIU));
|
||||
}
|
||||
|
||||
} // end namespace inferred_upcasting
|
||||
} // end anonymous namespace
|
||||
|
Loading…
Reference in New Issue
Block a user