[PATCH] D31890: Add support for unique_ptr<T> to dyn_cast<>

Zachary Turner via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 10 11:07:54 PDT 2017


zturner created this revision.

Currently it's possible to take a `T*` and cast it to a `U*` using llvm's casting mechanics, but it's not possible to take a `std::unique_ptr<T>` and cast it to a `std::unique_ptr<U>` even if they are compatible.  This patch adds this functionality.

I tried to modify the `cast` macros as well as the `dyn_cast` macros, but honestly the template mechanics started getting a little hairy and I wasn't able to get it working.  Upon further reflection, I decided that maybe we don't even want that behavior anyway, since if `T` is not a `U`, then no good can possibly come of casting it to one in the face of `unique_ptr`'s RAII semantics.  So hopefully I can get this in without adding `cast<>()` functionality, and then if/when someone actually needs `cast` functionality in the future, they can revisit this.


https://reviews.llvm.org/D31890

Files:
  llvm/include/llvm/Support/Casting.h
  llvm/unittests/Support/Casting.cpp


Index: llvm/unittests/Support/Casting.cpp
===================================================================
--- llvm/unittests/Support/Casting.cpp
+++ llvm/unittests/Support/Casting.cpp
@@ -150,6 +150,11 @@
   // EXPECT_EQ(F4, null_foo);
   foo *F5 = B1.daz();
   EXPECT_NE(F5, null_foo);
+
+  std::unique_ptr<const bar> BP(B2);
+  std::unique_ptr<const foo> FP = dyn_cast<foo>(BP);
+  EXPECT_NE(FP.get(), null_foo);
+  FP.release();
 }
 
 TEST(CastingTest, dyn_cast_or_null) {
@@ -163,6 +168,10 @@
   EXPECT_EQ(F4, null_foo);
   foo *F5 = B1.naz();
   EXPECT_NE(F5, null_foo);
+
+  std::unique_ptr<const bar> BP(fub());
+  std::unique_ptr<const foo> FP = dyn_cast_or_null<foo>(BP);
+  EXPECT_EQ(FP.get(), null_foo);
 }
 
 // These lines are errors...
Index: llvm/include/llvm/Support/Casting.h
===================================================================
--- llvm/include/llvm/Support/Casting.h
+++ llvm/include/llvm/Support/Casting.h
@@ -18,6 +18,7 @@
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/type_traits.h"
 #include <cassert>
+#include <memory>
 
 namespace llvm {
 
@@ -161,6 +162,17 @@
   typedef const To* ret_type;   // Constant pointer arg case, return const Ty*
 };
 
+struct bar;
+
+template <class To, class From>
+struct cast_retty_impl<To, std::unique_ptr<From>> {
+private:
+  typedef typename cast_retty_impl<To, From *>::ret_type PointerType;
+  typedef typename std::remove_pointer<PointerType>::type ResultType;
+
+public:
+  typedef std::unique_ptr<ResultType> ret_type;
+};
 
 template<class To, class From, class SimpleFrom>
 struct cast_retty_wrap {
@@ -298,6 +310,15 @@
   return isa<X>(Val) ? cast<X>(Val) : nullptr;
 }
 
+template <class X, class Y>
+LLVM_NODISCARD inline typename cast_retty<X, std::unique_ptr<Y>>::ret_type
+dyn_cast(std::unique_ptr<Y> &Val) {
+  if (!isa<X>(Val.get()))
+    return nullptr;
+  typedef typename cast_retty<X, std::unique_ptr<Y>>::ret_type ret_type;
+  return ret_type(cast<X>(Val.release()));
+}
+
 // dyn_cast_or_null<X> - Functionally identical to dyn_cast, except that a null
 // value is accepted.
 //
@@ -323,6 +344,14 @@
   return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
 }
 
+template <class X, class Y>
+LLVM_NODISCARD inline typename cast_retty<X, std::unique_ptr<Y>>::ret_type
+dyn_cast_or_null(std::unique_ptr<Y> &Val) {
+  if (!Val)
+    return nullptr;
+  return dyn_cast<X>(Val);
+}
+
 } // End llvm namespace
 
 #endif


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D31890.94687.patch
Type: text/x-patch
Size: 2431 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20170410/75e8cdbf/attachment.bin>


More information about the llvm-commits mailing list