summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDuncan P. N. Exon Smith <dexonsmith@apple.com>2014-11-24 03:13:02 +0000
committerDuncan P. N. Exon Smith <dexonsmith@apple.com>2014-11-24 03:13:02 +0000
commit5deb1bf97fbe56de1c8c9aab32f11fdac4f2a5fb (patch)
tree21961a294db810d8b190977a9731e7c9813d53e5
parent84d3252d1bc44a4a9ba322a8f58ababfcfb29674 (diff)
Support: Add *cast_or_null<> for pointer wrappers
Fill in omission of `cast_or_null<>` and `dyn_cast_or_null<>` for types that wrap pointers (e.g., smart pointers). Type traits need to be slightly stricter than for `cast<>` and `dyn_cast<>` to resolve ambiguities with simple types. There didn't seem to be any unit tests for pointer wrappers, so I tested `isa<>`, `cast<>`, and `dyn_cast<>` while I was in there. This only supports pointer wrappers with a conversion to `bool` to check for null. If in the future it's useful to support wrappers without such a conversion, it should be a straightforward incremental step to use the `simplify_type` machinery for the null check. In that case, the unit tests should be updated to remove the `operator bool()` from the `pointer_wrappers::PTy`. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@222644 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/Support/Casting.h34
-rw-r--r--unittests/Support/Casting.cpp96
2 files changed, 130 insertions, 0 deletions
diff --git a/include/llvm/Support/Casting.h b/include/llvm/Support/Casting.h
index beed31a4084..6ba5efa4755 100644
--- a/include/llvm/Support/Casting.h
+++ b/include/llvm/Support/Casting.h
@@ -243,6 +243,26 @@ inline typename cast_retty<X, Y *>::ret_type cast(Y *Val) {
// accepted.
//
template <class X, class Y>
+LLVM_ATTRIBUTE_UNUSED_RESULT inline typename std::enable_if<
+ !is_simple_type<Y>::value, typename cast_retty<X, const Y>::ret_type>::type
+cast_or_null(const Y &Val) {
+ if (!Val)
+ return nullptr;
+ assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!");
+ return cast<X>(Val);
+}
+
+template <class X, class Y>
+LLVM_ATTRIBUTE_UNUSED_RESULT inline typename std::enable_if<
+ !is_simple_type<Y>::value, typename cast_retty<X, Y>::ret_type>::type
+cast_or_null(Y &Val) {
+ if (!Val)
+ return nullptr;
+ assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!");
+ return cast<X>(Val);
+}
+
+template <class X, class Y>
LLVM_ATTRIBUTE_UNUSED_RESULT inline typename cast_retty<X, Y *>::ret_type
cast_or_null(Y *Val) {
if (!Val) return nullptr;
@@ -282,6 +302,20 @@ dyn_cast(Y *Val) {
// value is accepted.
//
template <class X, class Y>
+LLVM_ATTRIBUTE_UNUSED_RESULT inline typename std::enable_if<
+ !is_simple_type<Y>::value, typename cast_retty<X, const Y>::ret_type>::type
+dyn_cast_or_null(const Y &Val) {
+ return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
+}
+
+template <class X, class Y>
+LLVM_ATTRIBUTE_UNUSED_RESULT inline typename std::enable_if<
+ !is_simple_type<Y>::value, typename cast_retty<X, Y>::ret_type>::type
+dyn_cast_or_null(Y &Val) {
+ return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
+}
+
+template <class X, class Y>
LLVM_ATTRIBUTE_UNUSED_RESULT inline typename cast_retty<X, Y *>::ret_type
dyn_cast_or_null(Y *Val) {
return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
diff --git a/unittests/Support/Casting.cpp b/unittests/Support/Casting.cpp
index 88c7d19aa46..3218189eeab 100644
--- a/unittests/Support/Casting.cpp
+++ b/unittests/Support/Casting.cpp
@@ -232,3 +232,99 @@ namespace TemporaryCast {
struct pod {};
IllegalCast *testIllegalCast() { return cast<foo>(pod()); }
}
+
+namespace {
+namespace pointer_wrappers {
+
+struct Base {
+ bool IsDerived;
+ Base(bool IsDerived = false) : IsDerived(IsDerived) {}
+};
+
+struct Derived : Base {
+ Derived() : Base(true) {}
+ static bool classof(const Base *B) { return B->IsDerived; }
+};
+
+class PTy {
+ Base *B;
+public:
+ PTy(Base *B) : B(B) {}
+ LLVM_EXPLICIT operator bool() const { return get(); }
+ Base *get() const { return B; }
+};
+
+} // end namespace pointer_wrappers
+} // end namespace
+
+namespace llvm {
+
+template <> struct simplify_type<pointer_wrappers::PTy> {
+ typedef pointer_wrappers::Base *SimpleType;
+ static SimpleType getSimplifiedValue(pointer_wrappers::PTy &P) {
+ return P.get();
+ }
+};
+template <> struct simplify_type<const pointer_wrappers::PTy> {
+ typedef pointer_wrappers::Base *SimpleType;
+ static SimpleType getSimplifiedValue(const pointer_wrappers::PTy &P) {
+ return P.get();
+ }
+};
+
+} // end namespace llvm
+
+namespace {
+namespace pointer_wrappers {
+
+// Some objects.
+pointer_wrappers::Base B;
+pointer_wrappers::Derived D;
+
+// Mutable "smart" pointers.
+pointer_wrappers::PTy MN(nullptr);
+pointer_wrappers::PTy MB(&B);
+pointer_wrappers::PTy MD(&D);
+
+// Const "smart" pointers.
+const pointer_wrappers::PTy CN(nullptr);
+const pointer_wrappers::PTy CB(&B);
+const pointer_wrappers::PTy CD(&D);
+
+TEST(CastingTest, smart_isa) {
+ EXPECT_TRUE(!isa<pointer_wrappers::Derived>(MB));
+ EXPECT_TRUE(!isa<pointer_wrappers::Derived>(CB));
+ EXPECT_TRUE(isa<pointer_wrappers::Derived>(MD));
+ EXPECT_TRUE(isa<pointer_wrappers::Derived>(CD));
+}
+
+TEST(CastingTest, smart_cast) {
+ EXPECT_TRUE(cast<pointer_wrappers::Derived>(MD) == &D);
+ EXPECT_TRUE(cast<pointer_wrappers::Derived>(CD) == &D);
+}
+
+TEST(CastingTest, smart_cast_or_null) {
+ EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(MN) == nullptr);
+ EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(CN) == nullptr);
+ EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(MD) == &D);
+ EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(CD) == &D);
+}
+
+TEST(CastingTest, smart_dyn_cast) {
+ EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(MB) == nullptr);
+ EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(CB) == nullptr);
+ EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(MD) == &D);
+ EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(CD) == &D);
+}
+
+TEST(CastingTest, smart_dyn_cast_or_null) {
+ EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(MN) == nullptr);
+ EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(CN) == nullptr);
+ EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(MB) == nullptr);
+ EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(CB) == nullptr);
+ EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(MD) == &D);
+ EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(CD) == &D);
+}
+
+} // end namespace pointer_wrappers
+} // end namespace