[llvm] 716b9f7 - [LLVM][Support/ADT] Add assert for isPresent to dyn_cast.

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 6 13:59:05 PDT 2022


Author: bzcheeseman
Date: 2022-09-06T13:58:56-07:00
New Revision: 716b9f7a1a3ce7db89993c15855d8b89a35fc4fc

URL: https://github.com/llvm/llvm-project/commit/716b9f7a1a3ce7db89993c15855d8b89a35fc4fc
DIFF: https://github.com/llvm/llvm-project/commit/716b9f7a1a3ce7db89993c15855d8b89a35fc4fc.diff

LOG: [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

Added: 
    

Modified: 
    llvm/include/llvm/ADT/PointerUnion.h
    llvm/include/llvm/Support/Casting.h
    llvm/unittests/ADT/PointerUnionTest.cpp

Removed: 
    


################################################################################
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 <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

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 <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 {
@@ -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; }
 };
 
@@ -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>

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<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);
@@ -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);


        


More information about the llvm-commits mailing list