Skip to content

Commit

Permalink
[LLVM][Support/ADT] Add assert for isPresent to dyn_cast.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bzcheeseman committed Sep 6, 2022
1 parent 9006b08 commit 716b9f7
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 54 deletions.
2 changes: 1 addition & 1 deletion llvm/include/llvm/ADT/PointerUnion.h
Expand Up @@ -160,7 +160,7 @@ class PointerUnion
/// Returns the current pointer if it is of the specified pointer type,
/// otherwise returns null.
template <typename T> inline T dyn_cast() const {
return llvm::dyn_cast<T>(*this);
return llvm::dyn_cast_if_present<T>(*this);
}

/// If the union is set to the first pointer type get an address pointing to
Expand Down
74 changes: 39 additions & 35 deletions llvm/include/llvm/Support/Casting.h
Expand Up @@ -585,47 +585,18 @@ template <typename To, typename From>
return CastInfo<To, std::unique_ptr<From>>::doCast(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 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<Instruction>(myVal)) { ... }

template <typename To, typename From>
[[nodiscard]] inline decltype(auto) dyn_cast(const From &Val) {
return CastInfo<To, const From>::doCastIfPossible(Val);
}

template <typename To, typename From>
[[nodiscard]] inline decltype(auto) dyn_cast(From &Val) {
return CastInfo<To, From>::doCastIfPossible(Val);
}

template <typename To, typename From>
[[nodiscard]] inline decltype(auto) dyn_cast(From *Val) {
return CastInfo<To, From *>::doCastIfPossible(Val);
}

template <typename To, typename From>
[[nodiscard]] inline decltype(auto) dyn_cast(std::unique_ptr<From> &&Val) {
return CastInfo<To, std::unique_ptr<From>>::doCastIfPossible(std::move(Val));
}

//===----------------------------------------------------------------------===//
// ValueIsPresent
//===----------------------------------------------------------------------===//

template <typename T>
constexpr bool IsNullable = std::is_pointer<T>::value ||
std::is_constructible<T, std::nullptr_t>::value;
constexpr bool IsNullable =
std::is_pointer_v<T> || std::is_constructible_v<T, std::nullptr_t>;

/// 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 <typename T, typename Enable = void> struct ValueIsPresent {
Expand All @@ -646,7 +617,7 @@ template <typename T> struct ValueIsPresent<Optional<T>> {
template <typename T>
struct ValueIsPresent<T, std::enable_if_t<IsNullable<T>>> {
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; }
};

Expand All @@ -664,6 +635,39 @@ template <typename T> inline decltype(auto) unwrapValue(T &t) {
}
} // namespace detail

/// 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 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<Instruction>(myVal)) { ... }

template <typename To, typename From>
[[nodiscard]] inline decltype(auto) dyn_cast(const From &Val) {
assert(detail::isPresent(Val) && "dyn_cast on a non-existent value");
return CastInfo<To, const From>::doCastIfPossible(Val);
}

template <typename To, typename From>
[[nodiscard]] inline decltype(auto) dyn_cast(From &Val) {
assert(detail::isPresent(Val) && "dyn_cast on a non-existent value");
return CastInfo<To, From>::doCastIfPossible(Val);
}

template <typename To, typename From>
[[nodiscard]] inline decltype(auto) dyn_cast(From *Val) {
assert(detail::isPresent(Val) && "dyn_cast on a non-existent value");
return CastInfo<To, From *>::doCastIfPossible(Val);
}

template <typename To, typename From>
[[nodiscard]] inline decltype(auto) dyn_cast(std::unique_ptr<From> &&Val) {
assert(detail::isPresent(Val) && "dyn_cast on a non-existent value");
return CastInfo<To, std::unique_ptr<From>>::doCastIfPossible(
std::forward<std::unique_ptr<From> &&>(Val));
}

/// isa_and_present<X> - Functionally identical to isa, except that a null value
/// is accepted.
template <typename... X, class Y>
Expand Down
36 changes: 18 additions & 18 deletions llvm/unittests/ADT/PointerUnionTest.cpp
Expand Up @@ -227,8 +227,8 @@ TEST_F(PointerUnionTest, NewCastInfra) {
EXPECT_EQ(dyn_cast<float *>(b), nullptr);
EXPECT_EQ(dyn_cast<int *>(c), &i);
EXPECT_EQ(dyn_cast<float *>(c), nullptr);
EXPECT_EQ(dyn_cast<int *>(n), nullptr);
EXPECT_EQ(dyn_cast<float *>(n), nullptr);
EXPECT_EQ(dyn_cast_if_present<int *>(n), nullptr);
EXPECT_EQ(dyn_cast_if_present<float *>(n), nullptr);
EXPECT_EQ(dyn_cast<int *>(i3), &i);
EXPECT_EQ(dyn_cast<float *>(i3), nullptr);
EXPECT_EQ(dyn_cast<long long *>(i3), nullptr);
Expand All @@ -254,22 +254,22 @@ TEST_F(PointerUnionTest, NewCastInfra) {
EXPECT_EQ(dyn_cast<float *>(d4), nullptr);
EXPECT_EQ(dyn_cast<long long *>(d4), nullptr);
EXPECT_EQ(dyn_cast<double *>(d4), &d);
EXPECT_EQ(dyn_cast<int *>(i4null), nullptr);
EXPECT_EQ(dyn_cast<float *>(i4null), nullptr);
EXPECT_EQ(dyn_cast<long long *>(i4null), nullptr);
EXPECT_EQ(dyn_cast<double *>(i4null), nullptr);
EXPECT_EQ(dyn_cast<int *>(f4null), nullptr);
EXPECT_EQ(dyn_cast<float *>(f4null), nullptr);
EXPECT_EQ(dyn_cast<long long *>(f4null), nullptr);
EXPECT_EQ(dyn_cast<double *>(f4null), nullptr);
EXPECT_EQ(dyn_cast<int *>(l4null), nullptr);
EXPECT_EQ(dyn_cast<float *>(l4null), nullptr);
EXPECT_EQ(dyn_cast<long long *>(l4null), nullptr);
EXPECT_EQ(dyn_cast<double *>(l4null), nullptr);
EXPECT_EQ(dyn_cast<int *>(d4null), nullptr);
EXPECT_EQ(dyn_cast<float *>(d4null), nullptr);
EXPECT_EQ(dyn_cast<long long *>(d4null), nullptr);
EXPECT_EQ(dyn_cast<double *>(d4null), nullptr);
EXPECT_EQ(dyn_cast_if_present<int *>(i4null), nullptr);
EXPECT_EQ(dyn_cast_if_present<float *>(i4null), nullptr);
EXPECT_EQ(dyn_cast_if_present<long long *>(i4null), nullptr);
EXPECT_EQ(dyn_cast_if_present<double *>(i4null), nullptr);
EXPECT_EQ(dyn_cast_if_present<int *>(f4null), nullptr);
EXPECT_EQ(dyn_cast_if_present<float *>(f4null), nullptr);
EXPECT_EQ(dyn_cast_if_present<long long *>(f4null), nullptr);
EXPECT_EQ(dyn_cast_if_present<double *>(f4null), nullptr);
EXPECT_EQ(dyn_cast_if_present<int *>(l4null), nullptr);
EXPECT_EQ(dyn_cast_if_present<float *>(l4null), nullptr);
EXPECT_EQ(dyn_cast_if_present<long long *>(l4null), nullptr);
EXPECT_EQ(dyn_cast_if_present<double *>(l4null), nullptr);
EXPECT_EQ(dyn_cast_if_present<int *>(d4null), nullptr);
EXPECT_EQ(dyn_cast_if_present<float *>(d4null), nullptr);
EXPECT_EQ(dyn_cast_if_present<long long *>(d4null), nullptr);
EXPECT_EQ(dyn_cast_if_present<double *>(d4null), nullptr);

// test for const
const PU4 constd4(&d);
Expand Down

0 comments on commit 716b9f7

Please sign in to comment.