From 716b9f7a1a3ce7db89993c15855d8b89a35fc4fc Mon Sep 17 00:00:00 2001 From: bzcheeseman Date: Fri, 2 Sep 2022 10:23:43 -0700 Subject: [PATCH] [LLVM][Support/ADT] Add assert for isPresent to dyn_cast. This change adds an assert to dyn_cast that the value passed-in is present. In the past, this relied on the isa_impl assertion (which still works in many cases) but which we can tighten up for a better QoI. The PointerUnion change is because it seems like (based on the call sites) the semantics of the member dyn_cast are actually dyn_cast_if_present. Reviewed By: rriddle Differential Revision: https://reviews.llvm.org/D133221 --- llvm/include/llvm/ADT/PointerUnion.h | 2 +- llvm/include/llvm/Support/Casting.h | 74 +++++++++++++------------ llvm/unittests/ADT/PointerUnionTest.cpp | 36 ++++++------ 3 files changed, 58 insertions(+), 54 deletions(-) diff --git a/llvm/include/llvm/ADT/PointerUnion.h b/llvm/include/llvm/ADT/PointerUnion.h index f01db09dd765b..061c4000fcb35 100644 --- a/llvm/include/llvm/ADT/PointerUnion.h +++ b/llvm/include/llvm/ADT/PointerUnion.h @@ -160,7 +160,7 @@ class PointerUnion /// Returns the current pointer if it is of the specified pointer type, /// otherwise returns null. template inline T dyn_cast() const { - return llvm::dyn_cast(*this); + return llvm::dyn_cast_if_present(*this); } /// If the union is set to the first pointer type get an address pointing to diff --git a/llvm/include/llvm/Support/Casting.h b/llvm/include/llvm/Support/Casting.h index cf9c7c0efbf14..8a2fa94f9ccad 100644 --- a/llvm/include/llvm/Support/Casting.h +++ b/llvm/include/llvm/Support/Casting.h @@ -585,47 +585,18 @@ template return CastInfo>::doCast(std::move(Val)); } -/// dyn_cast - 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 be used to test for a type as well as cast if successful. The value -/// passed in must be present, if not, use dyn_cast_if_present. This should be -/// used in the context of an if statement like this: -/// -/// if (const Instruction *I = dyn_cast(myVal)) { ... } - -template -[[nodiscard]] inline decltype(auto) dyn_cast(const From &Val) { - return CastInfo::doCastIfPossible(Val); -} - -template -[[nodiscard]] inline decltype(auto) dyn_cast(From &Val) { - return CastInfo::doCastIfPossible(Val); -} - -template -[[nodiscard]] inline decltype(auto) dyn_cast(From *Val) { - return CastInfo::doCastIfPossible(Val); -} - -template -[[nodiscard]] inline decltype(auto) dyn_cast(std::unique_ptr &&Val) { - return CastInfo>::doCastIfPossible(std::move(Val)); -} - //===----------------------------------------------------------------------===// // ValueIsPresent //===----------------------------------------------------------------------===// template -constexpr bool IsNullable = std::is_pointer::value || - std::is_constructible::value; +constexpr bool IsNullable = + std::is_pointer_v || std::is_constructible_v; /// ValueIsPresent provides a way to check if a value is, well, present. For -/// pointers, this is the equivalent of checking against nullptr, for -/// Optionals this is the equivalent of checking hasValue(). It also -/// provides a method for unwrapping a value (think dereferencing a -/// pointer). +/// pointers, this is the equivalent of checking against nullptr, for Optionals +/// this is the equivalent of checking hasValue(). It also provides a method for +/// unwrapping a value (think calling .value() on an optional). // Generic values can't *not* be present. template struct ValueIsPresent { @@ -646,7 +617,7 @@ template struct ValueIsPresent> { template struct ValueIsPresent>> { using UnwrappedType = T; - static inline bool isPresent(const T &t) { return t != nullptr; } + static inline bool isPresent(const T &t) { return t != T(nullptr); } static inline decltype(auto) unwrapValue(T &t) { return t; } }; @@ -664,6 +635,39 @@ template inline decltype(auto) unwrapValue(T &t) { } } // namespace detail +/// dyn_cast - 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 be used to test for a type as well as cast if successful. The value +/// passed in must be present, if not, use dyn_cast_if_present. This should be +/// used in the context of an if statement like this: +/// +/// if (const Instruction *I = dyn_cast(myVal)) { ... } + +template +[[nodiscard]] inline decltype(auto) dyn_cast(const From &Val) { + assert(detail::isPresent(Val) && "dyn_cast on a non-existent value"); + return CastInfo::doCastIfPossible(Val); +} + +template +[[nodiscard]] inline decltype(auto) dyn_cast(From &Val) { + assert(detail::isPresent(Val) && "dyn_cast on a non-existent value"); + return CastInfo::doCastIfPossible(Val); +} + +template +[[nodiscard]] inline decltype(auto) dyn_cast(From *Val) { + assert(detail::isPresent(Val) && "dyn_cast on a non-existent value"); + return CastInfo::doCastIfPossible(Val); +} + +template +[[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)); +} + /// isa_and_present - Functionally identical to isa, except that a null value /// is accepted. template diff --git a/llvm/unittests/ADT/PointerUnionTest.cpp b/llvm/unittests/ADT/PointerUnionTest.cpp index e12a3ec4e4d4f..180ae45931ccb 100644 --- a/llvm/unittests/ADT/PointerUnionTest.cpp +++ b/llvm/unittests/ADT/PointerUnionTest.cpp @@ -227,8 +227,8 @@ TEST_F(PointerUnionTest, NewCastInfra) { EXPECT_EQ(dyn_cast(b), nullptr); EXPECT_EQ(dyn_cast(c), &i); EXPECT_EQ(dyn_cast(c), nullptr); - EXPECT_EQ(dyn_cast(n), nullptr); - EXPECT_EQ(dyn_cast(n), nullptr); + EXPECT_EQ(dyn_cast_if_present(n), nullptr); + EXPECT_EQ(dyn_cast_if_present(n), nullptr); EXPECT_EQ(dyn_cast(i3), &i); EXPECT_EQ(dyn_cast(i3), nullptr); EXPECT_EQ(dyn_cast(i3), nullptr); @@ -254,22 +254,22 @@ TEST_F(PointerUnionTest, NewCastInfra) { EXPECT_EQ(dyn_cast(d4), nullptr); EXPECT_EQ(dyn_cast(d4), nullptr); EXPECT_EQ(dyn_cast(d4), &d); - EXPECT_EQ(dyn_cast(i4null), nullptr); - EXPECT_EQ(dyn_cast(i4null), nullptr); - EXPECT_EQ(dyn_cast(i4null), nullptr); - EXPECT_EQ(dyn_cast(i4null), nullptr); - EXPECT_EQ(dyn_cast(f4null), nullptr); - EXPECT_EQ(dyn_cast(f4null), nullptr); - EXPECT_EQ(dyn_cast(f4null), nullptr); - EXPECT_EQ(dyn_cast(f4null), nullptr); - EXPECT_EQ(dyn_cast(l4null), nullptr); - EXPECT_EQ(dyn_cast(l4null), nullptr); - EXPECT_EQ(dyn_cast(l4null), nullptr); - EXPECT_EQ(dyn_cast(l4null), nullptr); - EXPECT_EQ(dyn_cast(d4null), nullptr); - EXPECT_EQ(dyn_cast(d4null), nullptr); - EXPECT_EQ(dyn_cast(d4null), nullptr); - EXPECT_EQ(dyn_cast(d4null), nullptr); + EXPECT_EQ(dyn_cast_if_present(i4null), nullptr); + EXPECT_EQ(dyn_cast_if_present(i4null), nullptr); + EXPECT_EQ(dyn_cast_if_present(i4null), nullptr); + EXPECT_EQ(dyn_cast_if_present(i4null), nullptr); + EXPECT_EQ(dyn_cast_if_present(f4null), nullptr); + EXPECT_EQ(dyn_cast_if_present(f4null), nullptr); + EXPECT_EQ(dyn_cast_if_present(f4null), nullptr); + EXPECT_EQ(dyn_cast_if_present(f4null), nullptr); + EXPECT_EQ(dyn_cast_if_present(l4null), nullptr); + EXPECT_EQ(dyn_cast_if_present(l4null), nullptr); + EXPECT_EQ(dyn_cast_if_present(l4null), nullptr); + EXPECT_EQ(dyn_cast_if_present(l4null), nullptr); + EXPECT_EQ(dyn_cast_if_present(d4null), nullptr); + EXPECT_EQ(dyn_cast_if_present(d4null), nullptr); + EXPECT_EQ(dyn_cast_if_present(d4null), nullptr); + EXPECT_EQ(dyn_cast_if_present(d4null), nullptr); // test for const const PU4 constd4(&d);