diff --git a/llvm/include/llvm/Support/Casting.h b/llvm/include/llvm/Support/Casting.h --- a/llvm/include/llvm/Support/Casting.h +++ b/llvm/include/llvm/Support/Casting.h @@ -351,10 +351,10 @@ static inline CastResultType castFailed() { return CastResultType(nullptr); } - static inline CastResultType doCastIfPossible(std::unique_ptr &&f) { - if (!Self::isPossible(f)) + static inline CastResultType doCastIfPossible(std::unique_ptr &f) { + if (!Self::isPossible(f.get())) return castFailed(); - return doCast(f); + return doCast(std::move(f)); } }; @@ -664,10 +664,9 @@ } template -[[nodiscard]] inline decltype(auto) dyn_cast(std::unique_ptr &&Val) { +[[nodiscard]] inline decltype(auto) dyn_cast(std::unique_ptr &Val) { assert(detail::isPresent(Val) && "dyn_cast on a non-existent value"); - return CastInfo>::doCastIfPossible( - std::forward &&>(Val)); + return CastInfo>::doCastIfPossible(Val); } /// isa_and_present - Functionally identical to isa, except that a null value diff --git a/llvm/unittests/Support/Casting.cpp b/llvm/unittests/Support/Casting.cpp --- a/llvm/unittests/Support/Casting.cpp +++ b/llvm/unittests/Support/Casting.cpp @@ -45,6 +45,10 @@ static bool classof(const base *B) { return true; } }; +struct derived_nocast : public base { + static bool classof(const base *B) { return false; } +}; + template <> struct isa_impl { static inline bool doit(const bar &Val) { dbgs() << "Classof: " << &Val << "\n"; @@ -212,6 +216,18 @@ // EXPECT_EQ(F4, null_foo); foo *F5 = B1.daz(); EXPECT_NE(F5, null_foo); + + auto BP = std::make_unique(); + auto FP = dyn_cast(BP); + static_assert(std::is_same_v, decltype(FP)>, + "Incorrect deduced return type!"); + EXPECT_NE(FP.get(), nullptr); + EXPECT_EQ(BP.get(), nullptr); + + auto BP2 = std::make_unique(); + auto DP = dyn_cast(BP2); + EXPECT_EQ(DP.get(), nullptr); + EXPECT_NE(BP2.get(), nullptr); } // All these tests forward to dyn_cast_if_present, so they also provde an