[llvm] r222644 - Support: Add *cast_or_null<> for pointer wrappers

David Blaikie dblaikie at gmail.com
Wed Dec 3 14:00:07 PST 2014


On Fri, Nov 28, 2014 at 6:14 PM, Duncan P. N. Exon Smith <
dexonsmith at apple.com> wrote:

>
> > On 2014 Nov 24, at 09:01, David Blaikie <dblaikie at gmail.com> wrote:
> >
> >
> >
> > On Sun, Nov 23, 2014 at 7:13 PM, Duncan P. N. Exon Smith <
> dexonsmith at apple.com> wrote:
> > Author: dexonsmith
> > Date: Sun Nov 23 21:13:02 2014
> > New Revision: 222644
> >
> > URL: http://llvm.org/viewvc/llvm-project?rev=222644&view=rev
> > Log:
> > Support: Add *cast_or_null<> for pointer wrappers
> >
> > 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))
>
> Well, yes, but not only `unique_ptr<>`.  My motivating use case is a
> yet-to-be-committed pointer-wrapper for `Metadata` operands, similar
> to `Use` for `Value`.
>
> I think testing a dumb pointer-wrapper directly matches better how
> `simpify_type` is implemented.  And it's a bit more flexible if at
> some point we want to support a type that supports `simplify_type`
> but doesn't have an `operator bool()`.
>

Hmm, OK. (we could use "== nullptr" as the boolean test, rather than
operator bool, not sure either's better, so long as it can cope with
explicit operator bool, which I see you tested)


>
> >
> > In some cases, we actually want ownership transfer:
> >
> >   unique_ptr<Base> b = ...;
> >   unique_ptr<Derived> d = dyn_cast<Derived>(b);
> >   assert(b ^ d);
> >
> > 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(?))
>
> I agree we would need different names, but I'm not sure it fits in
> the same library -- these are meant to be lightweight RTTI
> replacements.  Ownership transfer seems perpendicular to RTTI.
>

Except it unfortunately isn't - see
http://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast - mostly
because those shared_ptr is more finicky to transfer ownership while
changing types, etc. So there aren't equivalents for unique_ptr - but like
make_shared, there's some convenience in also having make_unique (& thus in
having unique_casts).


> Nevertheless, I wouldn't be against having convenient wrappers for
> casting+transfer if we have enough use cases for it...
>

*nod* some day, perhaps


>
> >
> >
> > Fill in omission of `cast_or_null<>` and `dyn_cast_or_null<>` for types
> > that wrap pointers (e.g., smart pointers).
> >
> > Type traits need to be slightly stricter than for `cast<>` and
> > `dyn_cast<>` to resolve ambiguities with simple types.
> >
> > There didn't seem to be any unit tests for pointer wrappers, so I tested
> > `isa<>`, `cast<>`, and `dyn_cast<>` while I was in there.
> >
> > This only supports pointer wrappers with a conversion to `bool` to check
> > for null.  If in the future it's useful to support wrappers without such
> > a conversion, it should be a straightforward incremental step to use the
> > `simplify_type` machinery for the null check.  In that case, the unit
> > tests should be updated to remove the `operator bool()` from the
> > `pointer_wrappers::PTy`.
> >
> > Modified:
> >     llvm/trunk/include/llvm/Support/Casting.h
> >     llvm/trunk/unittests/Support/Casting.cpp
> >
> > Modified: llvm/trunk/include/llvm/Support/Casting.h
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Casting.h?rev=222644&r1=222643&r2=222644&view=diff
> >
> ==============================================================================
> > --- llvm/trunk/include/llvm/Support/Casting.h (original)
> > +++ llvm/trunk/include/llvm/Support/Casting.h Sun Nov 23 21:13:02 2014
> > @@ -243,6 +243,26 @@ inline typename cast_retty<X, Y *>::ret_
> >  // accepted.
> >  //
> >  template <class X, class Y>
> > +LLVM_ATTRIBUTE_UNUSED_RESULT inline typename std::enable_if<
> > +    !is_simple_type<Y>::value, typename cast_retty<X, const
> Y>::ret_type>::type
> > +cast_or_null(const Y &Val) {
> > +  if (!Val)
> > +    return nullptr;
> > +  assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible
> type!");
> > +  return cast<X>(Val);
> > +}
> > +
> > +template <class X, class Y>
> > +LLVM_ATTRIBUTE_UNUSED_RESULT inline typename std::enable_if<
> > +    !is_simple_type<Y>::value, typename cast_retty<X,
> Y>::ret_type>::type
> > +cast_or_null(Y &Val) {
> > +  if (!Val)
> > +    return nullptr;
> > +  assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible
> type!");
> > +  return cast<X>(Val);
> > +}
> > +
> > +template <class X, class Y>
> >  LLVM_ATTRIBUTE_UNUSED_RESULT inline typename cast_retty<X, Y
> *>::ret_type
> >  cast_or_null(Y *Val) {
> >    if (!Val) return nullptr;
> > @@ -282,6 +302,20 @@ dyn_cast(Y *Val) {
> >  // value is accepted.
> >  //
> >  template <class X, class Y>
> > +LLVM_ATTRIBUTE_UNUSED_RESULT inline typename std::enable_if<
> > +    !is_simple_type<Y>::value, typename cast_retty<X, const
> Y>::ret_type>::type
> > +dyn_cast_or_null(const Y &Val) {
> > +  return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
> > +}
> > +
> > +template <class X, class Y>
> > +LLVM_ATTRIBUTE_UNUSED_RESULT inline typename std::enable_if<
> > +    !is_simple_type<Y>::value, typename cast_retty<X,
> Y>::ret_type>::type
> > +dyn_cast_or_null(Y &Val) {
> > +  return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
> > +}
> > +
> > +template <class X, class Y>
> >  LLVM_ATTRIBUTE_UNUSED_RESULT inline typename cast_retty<X, Y
> *>::ret_type
> >  dyn_cast_or_null(Y *Val) {
> >    return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
> >
> > Modified: llvm/trunk/unittests/Support/Casting.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/Casting.cpp?rev=222644&r1=222643&r2=222644&view=diff
> >
> ==============================================================================
> > --- llvm/trunk/unittests/Support/Casting.cpp (original)
> > +++ llvm/trunk/unittests/Support/Casting.cpp Sun Nov 23 21:13:02 2014
> > @@ -232,3 +232,99 @@ namespace TemporaryCast {
> >  struct pod {};
> >  IllegalCast *testIllegalCast() { return cast<foo>(pod()); }
> >  }
> > +
> > +namespace {
> > +namespace pointer_wrappers {
> > +
> > +struct Base {
> > +  bool IsDerived;
> > +  Base(bool IsDerived = false) : IsDerived(IsDerived) {}
> > +};
> > +
> > +struct Derived : Base {
> > +  Derived() : Base(true) {}
> > +  static bool classof(const Base *B) { return B->IsDerived; }
> > +};
> > +
> > +class PTy {
> > +  Base *B;
> > +public:
> > +  PTy(Base *B) : B(B) {}
> > +  LLVM_EXPLICIT operator bool() const { return get(); }
> > +  Base *get() const { return B; }
> > +};
> > +
> > +} // end namespace pointer_wrappers
> > +} // end namespace
> > +
> > +namespace llvm {
> > +
> > +template <> struct simplify_type<pointer_wrappers::PTy> {
> > +  typedef pointer_wrappers::Base *SimpleType;
> > +  static SimpleType getSimplifiedValue(pointer_wrappers::PTy &P) {
> > +    return P.get();
> > +  }
> > +};
> > +template <> struct simplify_type<const pointer_wrappers::PTy> {
> > +  typedef pointer_wrappers::Base *SimpleType;
> > +  static SimpleType getSimplifiedValue(const pointer_wrappers::PTy &P) {
> > +    return P.get();
> > +  }
> > +};
> > +
> > +} // end namespace llvm
> > +
> > +namespace {
> > +namespace pointer_wrappers {
> > +
> > +// Some objects.
> > +pointer_wrappers::Base B;
> > +pointer_wrappers::Derived D;
> > +
> > +// Mutable "smart" pointers.
> > +pointer_wrappers::PTy MN(nullptr);
> > +pointer_wrappers::PTy MB(&B);
> > +pointer_wrappers::PTy MD(&D);
> > +
> > +// Const "smart" pointers.
> > +const pointer_wrappers::PTy CN(nullptr);
> > +const pointer_wrappers::PTy CB(&B);
> > +const pointer_wrappers::PTy CD(&D);
> > +
> > +TEST(CastingTest, smart_isa) {
> > +  EXPECT_TRUE(!isa<pointer_wrappers::Derived>(MB));
> > +  EXPECT_TRUE(!isa<pointer_wrappers::Derived>(CB));
> > +  EXPECT_TRUE(isa<pointer_wrappers::Derived>(MD));
> > +  EXPECT_TRUE(isa<pointer_wrappers::Derived>(CD));
> > +}
> > +
> > +TEST(CastingTest, smart_cast) {
> > +  EXPECT_TRUE(cast<pointer_wrappers::Derived>(MD) == &D);
> > +  EXPECT_TRUE(cast<pointer_wrappers::Derived>(CD) == &D);
> > +}
> > +
> > +TEST(CastingTest, smart_cast_or_null) {
> > +  EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(MN) == nullptr);
> > +  EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(CN) == nullptr);
> > +  EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(MD) == &D);
> > +  EXPECT_TRUE(cast_or_null<pointer_wrappers::Derived>(CD) == &D);
> > +}
> > +
> > +TEST(CastingTest, smart_dyn_cast) {
> > +  EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(MB) == nullptr);
> > +  EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(CB) == nullptr);
> > +  EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(MD) == &D);
> > +  EXPECT_TRUE(dyn_cast<pointer_wrappers::Derived>(CD) == &D);
> > +}
> > +
> > +TEST(CastingTest, smart_dyn_cast_or_null) {
> > +  EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(MN) ==
> nullptr);
> > +  EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(CN) ==
> nullptr);
> > +  EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(MB) ==
> nullptr);
> > +  EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(CB) ==
> nullptr);
> > +  EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(MD) == &D);
> > +  EXPECT_TRUE(dyn_cast_or_null<pointer_wrappers::Derived>(CD) == &D);
> > +}
> > +
> > +} // end namespace pointer_wrappers
> > +} // end namespace
> >
> >
> > _______________________________________________
> > llvm-commits mailing list
> > llvm-commits at cs.uiuc.edu
> > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
> >
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20141203/22cca0ab/attachment.html>


More information about the llvm-commits mailing list