#include "llvm/Support/Compiler.h"
#include "llvm/Support/type_traits.h"
#include <cassert>
+#include <memory>
namespace llvm {
}
};
+template <typename To, typename From>
+struct isa_impl_cl<To, const std::unique_ptr<From>> {
+ static inline bool doit(const std::unique_ptr<From> &Val) {
+ assert(Val && "isa<> used on a null pointer");
+ return isa_impl_cl<To, From>::doit(*Val);
+ }
+};
+
template <typename To, typename From> struct isa_impl_cl<To, From*> {
static inline bool doit(const From *Val) {
assert(Val && "isa<> used on a null pointer");
typedef const To* ret_type; // Constant pointer arg case, return const Ty*
};
+template <class To, class From>
+struct cast_retty_impl<To, std::unique_ptr<From>> {
+private:
+ typedef typename cast_retty_impl<To, From *>::ret_type PointerType;
+ typedef typename std::remove_pointer<PointerType>::type ResultType;
+
+public:
+ typedef std::unique_ptr<ResultType> ret_type;
+};
template<class To, class From, class SimpleFrom>
struct cast_retty_wrap {
typename simplify_type<Y*>::SimpleType>::doit(Val);
}
+template <class X, class Y>
+inline typename cast_retty<X, std::unique_ptr<Y>>::ret_type
+cast(std::unique_ptr<Y> &&Val) {
+ assert(isa<X>(Val.get()) && "cast<Ty>() argument of incompatible type!");
+ using ret_type = typename cast_retty<X, std::unique_ptr<Y>>::ret_type;
+ return ret_type(
+ cast_convert_val<X, Y *, typename simplify_type<Y *>::SimpleType>::doit(
+ Val.release()));
+}
+
// cast_or_null<X> - Functionally identical to cast, except that a null value is
// accepted.
//
return cast<X>(Val);
}
+template <class X, class Y>
+inline typename cast_retty<X, std::unique_ptr<Y>>::ret_type
+cast_or_null(std::unique_ptr<Y> &&Val) {
+ if (!Val)
+ return nullptr;
+ return cast<X>(std::move(Val));
+}
// dyn_cast<X> - Return the argument parameter cast to the specified type. This
// casting operator returns null if the argument is of the wrong type, so it can
return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
}
+// unique_dyn_cast<X> - Given a unique_ptr<Y>, try to return a unique_ptr<X>,
+// taking ownership of the input pointer iff isa<X>(Val) is true. If the
+// cast is successful, From refers to nullptr on exit and the casted value
+// is returned. If the cast is unsuccessful, the function returns nullptr
+// and From is unchanged.
+template <class X, class Y>
+LLVM_NODISCARD inline auto unique_dyn_cast(std::unique_ptr<Y> &Val)
+ -> decltype(cast<X>(Val)) {
+ if (!isa<X>(Val))
+ return nullptr;
+ return cast<X>(std::move(Val));
+}
+
+template <class X, class Y>
+LLVM_NODISCARD inline auto unique_dyn_cast(std::unique_ptr<Y> &&Val)
+ -> decltype(cast<X>(Val)) {
+ return unique_dyn_cast<X, Y>(Val);
+}
+
+// dyn_cast_or_null<X> - Functionally identical to unique_dyn_cast, except that
+// a null value is accepted.
+template <class X, class Y>
+LLVM_NODISCARD inline auto unique_dyn_cast_or_null(std::unique_ptr<Y> &Val)
+ -> decltype(cast<X>(Val)) {
+ if (!Val)
+ return nullptr;
+ return unique_dyn_cast(Val);
+}
+
+template <class X, class Y>
+LLVM_NODISCARD inline auto unique_dyn_cast_or_null(std::unique_ptr<Y> &&Val)
+ -> decltype(cast<X>(Val)) {
+ return unique_dyn_cast_or_null<X, Y>(Val);
+}
+
} // End llvm namespace
#endif
}*/
};
+struct base {
+ virtual ~base() {}
+};
+
+struct derived : public base {
+ static bool classof(const base *B) { return true; }
+};
+
template <> struct isa_impl<foo, bar> {
static inline bool doit(const bar &Val) {
dbgs() << "Classof: " << &Val << "\n";
}
};
+template <typename T> struct isa_impl<foo, T> {
+ static inline bool doit(const T &Val) { return false; }
+};
+
foo *bar::baz() {
return cast<foo>(this);
}
// EXPECT_EQ(F7, null_foo);
foo *F8 = B1.baz();
EXPECT_NE(F8, null_foo);
+
+ std::unique_ptr<const bar> BP(B2);
+ auto FP = cast<foo>(std::move(BP));
+ static_assert(std::is_same<std::unique_ptr<const foo>, decltype(FP)>::value,
+ "Incorrect deduced return type!");
+ EXPECT_NE(FP.get(), null_foo);
+ FP.release();
}
TEST(CastingTest, cast_or_null) {
EXPECT_EQ(F14, null_foo);
foo *F15 = B1.caz();
EXPECT_NE(F15, null_foo);
+
+ std::unique_ptr<const bar> BP(fub());
+ auto FP = cast_or_null<foo>(std::move(BP));
+ EXPECT_EQ(FP.get(), null_foo);
}
TEST(CastingTest, dyn_cast) {
EXPECT_NE(F5, null_foo);
}
+std::unique_ptr<derived> newd() { return llvm::make_unique<derived>(); }
+std::unique_ptr<base> newb() { return llvm::make_unique<derived>(); }
+
+TEST(CastingTest, unique_dyn_cast) {
+ derived *OrigD = nullptr;
+ auto D = llvm::make_unique<derived>();
+ OrigD = D.get();
+
+ // Converting from D to itself is valid, it should return a new unique_ptr
+ // and the old one should become nullptr.
+ auto NewD = unique_dyn_cast<derived>(D);
+ ASSERT_EQ(OrigD, NewD.get());
+ ASSERT_EQ(nullptr, D);
+
+ // Converting from D to B is valid, B should have a value and D should be
+ // nullptr.
+ auto B = unique_dyn_cast<base>(NewD);
+ ASSERT_EQ(OrigD, B.get());
+ ASSERT_EQ(nullptr, NewD);
+
+ // Converting from B to itself is valid, it should return a new unique_ptr
+ // and the old one should become nullptr.
+ auto NewB = unique_dyn_cast<base>(B);
+ ASSERT_EQ(OrigD, NewB.get());
+ ASSERT_EQ(nullptr, B);
+
+ // Converting from B to D is valid, D should have a value and B should be
+ // nullptr;
+ D = unique_dyn_cast<derived>(NewB);
+ ASSERT_EQ(OrigD, D.get());
+ ASSERT_EQ(nullptr, NewB);
+
+ // Converting between unrelated types should fail. The original value should
+ // remain unchanged and it should return nullptr.
+ auto F = unique_dyn_cast<foo>(D);
+ ASSERT_EQ(nullptr, F);
+ ASSERT_EQ(OrigD, D.get());
+
+ // All of the above should also hold for temporaries.
+ auto D2 = unique_dyn_cast<derived>(newd());
+ EXPECT_NE(nullptr, D2);
+
+ auto B2 = unique_dyn_cast<derived>(newb());
+ EXPECT_NE(nullptr, B2);
+
+ auto B3 = unique_dyn_cast<base>(newb());
+ EXPECT_NE(nullptr, B3);
+
+ auto F2 = unique_dyn_cast<foo>(newb());
+ EXPECT_EQ(nullptr, F2);
+}
+
// These lines are errors...
//foo *F20 = cast<foo>(B2); // Yields const foo*
//foo &F21 = cast<foo>(B3); // Yields const foo&