Index: llvm/include/llvm/Support/Casting.h =================================================================== --- llvm/include/llvm/Support/Casting.h +++ llvm/include/llvm/Support/Casting.h @@ -358,6 +358,41 @@ return (Val && isa(Val)) ? cast(Val) : nullptr; } +// unique_dyn_cast - Given a unique_ptr, try to return a unique_ptr, +// taking ownership of the input pointer iff isa(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 +LLVM_NODISCARD inline auto unique_dyn_cast(std::unique_ptr &Val) + -> decltype(cast(Val)) { + if (!isa(Val)) + return nullptr; + return cast(std::move(Val)); +} + +template +LLVM_NODISCARD inline auto unique_dyn_cast(std::unique_ptr &&Val) + -> decltype(cast(Val)) { + return unique_dyn_cast(Val); +} + +// dyn_cast_or_null - Functionally identical to unique_dyn_cast, except that +// a null value is accepted. +template +LLVM_NODISCARD inline auto unique_dyn_cast_or_null(std::unique_ptr &Val) + -> decltype(cast(Val)) { + if (!Val) + return nullptr; + return unique_dyn_cast(Val); +} + +template +LLVM_NODISCARD inline auto unique_dyn_cast_or_null(std::unique_ptr &&Val) + -> decltype(cast(Val)) { + return unique_dyn_cast_or_null(Val); +} + } // End llvm namespace #endif Index: llvm/unittests/Support/Casting.cpp =================================================================== --- llvm/unittests/Support/Casting.cpp +++ llvm/unittests/Support/Casting.cpp @@ -40,6 +40,14 @@ }*/ }; +struct base { + virtual ~base() {} +}; + +struct derived : public base { + static bool classof(const base *B) { return true; } +}; + template <> struct isa_impl { static inline bool doit(const bar &Val) { dbgs() << "Classof: " << &Val << "\n"; @@ -47,6 +55,10 @@ } }; +template struct isa_impl { + static inline bool doit(const T &Val) { return false; } +}; + foo *bar::baz() { return cast(this); } @@ -176,6 +188,58 @@ EXPECT_NE(F5, null_foo); } +std::unique_ptr newd() { return llvm::make_unique(); } +std::unique_ptr newb() { return llvm::make_unique(); } + +TEST(CastingTest, unique_dyn_cast) { + derived *OrigD = nullptr; + auto D = llvm::make_unique(); + 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(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(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(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(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(D); + ASSERT_EQ(nullptr, F); + ASSERT_EQ(OrigD, D.get()); + + // All of the above should also hold for temporaries. + auto D2 = unique_dyn_cast(newd()); + EXPECT_NE(nullptr, D2); + + auto B2 = unique_dyn_cast(newb()); + EXPECT_NE(nullptr, B2); + + auto B3 = unique_dyn_cast(newb()); + EXPECT_NE(nullptr, B3); + + auto F2 = unique_dyn_cast(newb()); + EXPECT_EQ(nullptr, F2); +} + // These lines are errors... //foo *F20 = cast(B2); // Yields const foo* //foo &F21 = cast(B3); // Yields const foo&