<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Sun, Nov 23, 2014 at 7:13 PM, Duncan P. N. Exon Smith <span dir="ltr"><<a href="mailto:dexonsmith@apple.com" target="_blank">dexonsmith@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: dexonsmith<br>
Date: Sun Nov 23 21:13:02 2014<br>
New Revision: 222644<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=222644&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=222644&view=rev</a><br>
Log:<br>
Support: Add *cast_or_null<> for pointer wrappers<br></blockquote><div><br></div><div>I'm assuming this is intended to work with unique_ptr? (is it worth testing with unique_ptr itself, then? (I'm honestly not sure))<br><br>In some cases, we actually want ownership transfer:<br><br>  unique_ptr<Base> b = ...;<br>  unique_ptr<Derived> d = dyn_cast<Derived>(b);<br>  assert(b ^ d);<br><br>But I guess it's probably not the right thing to use the existing names/templates for this task? (if we mostly /don't/ want to transfer ownership, which I guess is probably the case(?)) Maybe we'll eventually add some new names for this (*cast*_transfer(?))</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Fill in omission of `cast_or_null<>` and `dyn_cast_or_null<>` for types<br>
that wrap pointers (e.g., smart pointers).<br>
<br>
Type traits need to be slightly stricter than for `cast<>` and<br>
`dyn_cast<>` to resolve ambiguities with simple types.<br>
<br>
There didn't seem to be any unit tests for pointer wrappers, so I tested<br>
`isa<>`, `cast<>`, and `dyn_cast<>` while I was in there.<br>
<br>
This only supports pointer wrappers with a conversion to `bool` to check<br>
for null.  If in the future it's useful to support wrappers without such<br>
a conversion, it should be a straightforward incremental step to use the<br>
`simplify_type` machinery for the null check.  In that case, the unit<br>
tests should be updated to remove the `operator bool()` from the<br>
`pointer_wrappers::PTy`.<br>
<br>
Modified:<br>
    llvm/trunk/include/llvm/Support/Casting.h<br>
    llvm/trunk/unittests/Support/Casting.cpp<br>
<br>
Modified: llvm/trunk/include/llvm/Support/Casting.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Casting.h?rev=222644&r1=222643&r2=222644&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Casting.h?rev=222644&r1=222643&r2=222644&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/Support/Casting.h (original)<br>
+++ llvm/trunk/include/llvm/Support/Casting.h Sun Nov 23 21:13:02 2014<br>
@@ -243,6 +243,26 @@ inline typename cast_retty<X, Y *>::ret_<br>
 // accepted.<br>
 //<br>
 template <class X, class Y><br>
+LLVM_ATTRIBUTE_UNUSED_RESULT inline typename std::enable_if<<br>
+    !is_simple_type<Y>::value, typename cast_retty<X, const Y>::ret_type>::type<br>
+cast_or_null(const Y &Val) {<br>
+  if (!Val)<br>
+    return nullptr;<br>
+  assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!");<br>
+  return cast<X>(Val);<br>
+}<br>
+<br>
+template <class X, class Y><br>
+LLVM_ATTRIBUTE_UNUSED_RESULT inline typename std::enable_if<<br>
+    !is_simple_type<Y>::value, typename cast_retty<X, Y>::ret_type>::type<br>
+cast_or_null(Y &Val) {<br>
+  if (!Val)<br>
+    return nullptr;<br>
+  assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!");<br>
+  return cast<X>(Val);<br>
+}<br>
+<br>
+template <class X, class Y><br>
 LLVM_ATTRIBUTE_UNUSED_RESULT inline typename cast_retty<X, Y *>::ret_type<br>
 cast_or_null(Y *Val) {<br>
   if (!Val) return nullptr;<br>
@@ -282,6 +302,20 @@ dyn_cast(Y *Val) {<br>
 // value is accepted.<br>
 //<br>
 template <class X, class Y><br>
+LLVM_ATTRIBUTE_UNUSED_RESULT inline typename std::enable_if<<br>
+    !is_simple_type<Y>::value, typename cast_retty<X, const Y>::ret_type>::type<br>
+dyn_cast_or_null(const Y &Val) {<br>
+  return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;<br>
+}<br>
+<br>
+template <class X, class Y><br>
+LLVM_ATTRIBUTE_UNUSED_RESULT inline typename std::enable_if<<br>
+    !is_simple_type<Y>::value, typename cast_retty<X, Y>::ret_type>::type<br>
+dyn_cast_or_null(Y &Val) {<br>
+  return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;<br>
+}<br>
+<br>
+template <class X, class Y><br>
 LLVM_ATTRIBUTE_UNUSED_RESULT inline typename cast_retty<X, Y *>::ret_type<br>
 dyn_cast_or_null(Y *Val) {<br>
   return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;<br>
<br>
Modified: llvm/trunk/unittests/Support/Casting.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/Casting.cpp?rev=222644&r1=222643&r2=222644&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/Casting.cpp?rev=222644&r1=222643&r2=222644&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/unittests/Support/Casting.cpp (original)<br>
+++ llvm/trunk/unittests/Support/Casting.cpp Sun Nov 23 21:13:02 2014<br>
@@ -232,3 +232,99 @@ namespace TemporaryCast {<br>
 struct pod {};<br>
 IllegalCast *testIllegalCast() { return cast<foo>(pod()); }<br>
 }<br>
+<br>
+namespace {<br>
+namespace pointer_wrappers {<br>
+<br>
+struct Base {<br>
+  bool IsDerived;<br>
+  Base(bool IsDerived = false) : IsDerived(IsDerived) {}<br>
+};<br>
+<br>
+struct Derived : Base {<br>
+  Derived() : Base(true) {}<br>
+  static bool classof(const Base *B) { return B->IsDerived; }<br>
+};<br>
+<br>
+class PTy {<br>
+  Base *B;<br>
+public:<br>
+  PTy(Base *B) : B(B) {}<br>
+  LLVM_EXPLICIT operator bool() const { return get(); }<br>
+  Base *get() const { return B; }<br>
+};<br>
+<br>
+} // end namespace pointer_wrappers<br>
+} // end namespace<br>
+<br>
+namespace llvm {<br>
+<br>
+template <> struct simplify_type<pointer_wrappers::PTy> {<br>
+  typedef pointer_wrappers::Base *SimpleType;<br>
+  static SimpleType getSimplifiedValue(pointer_wrappers::PTy &P) {<br>
+    return P.get();<br>
+  }<br>
+};<br>
+template <> struct simplify_type<const pointer_wrappers::PTy> {<br>
+  typedef pointer_wrappers::Base *SimpleType;<br>
+  static SimpleType getSimplifiedValue(const pointer_wrappers::PTy &P) {<br>
+    return P.get();<br>
+  }<br>
+};<br>
+<br>
+} // end namespace llvm<br>
+<br>
+namespace {<br>
+namespace pointer_wrappers {<br>
+<br>
+// Some objects.<br>
+pointer_wrappers::Base B;<br>
+pointer_wrappers::Derived D;<br>
+<br>
+// Mutable "smart" pointers.<br>
+pointer_wrappers::PTy MN(nullptr);<br>
+pointer_wrappers::PTy MB(&B);<br>
+pointer_wrappers::PTy MD(&D);<br>
+<br>
+// Const "smart" pointers.<br>
+const pointer_wrappers::PTy CN(nullptr);<br>
+const pointer_wrappers::PTy CB(&B);<br>
+const pointer_wrappers::PTy CD(&D);<br>
+<br>
+TEST(CastingTest, smart_isa) {<br>
+  EXPECT_TRUE(!isa<pointer_wrappers::Derived>(MB));<br>
+  EXPECT_TRUE(!isa<pointer_wrappers::Derived>(CB));<br>
+  EXPECT_TRUE(isa<pointer_wrappers::Derived>(MD));<br>
+  EXPECT_TRUE(isa<pointer_wrappers::Derived>(CD));<br>
+}<br>
+<br>
+TEST(CastingTest, smart_cast) {<br>
+  EXPECT_TRUE(cast<pointer_wrappers::Derived>(MD) == &D);<br>
+  EXPECT_TRUE(cast<pointer_wrappers::Derived>(CD) == &D);<br>
+}<br>
+<br>
+TEST(CastingTest, smart_cast_or_null) {<br>
+  EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(MN) == nullptr);<br>
+  EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(CN) == nullptr);<br>
+  EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(MD) == &D);<br>
+  EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(CD) == &D);<br>
+}<br>
+<br>
+TEST(CastingTest, smart_dyn_cast) {<br>
+  EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(MB) == nullptr);<br>
+  EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(CB) == nullptr);<br>
+  EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(MD) == &D);<br>
+  EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(CD) == &D);<br>
+}<br>
+<br>
+TEST(CastingTest, smart_dyn_cast_or_null) {<br>
+  EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(MN) == nullptr);<br>
+  EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(CN) == nullptr);<br>
+  EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(MB) == nullptr);<br>
+  EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(CB) == nullptr);<br>
+  EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(MD) == &D);<br>
+  EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(CD) == &D);<br>
+}<br>
+<br>
+} // end namespace pointer_wrappers<br>
+} // end namespace<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div></div>