[PATCH] D15910: Make isa, cast, dyn_cast, etc. work with std::unique_ptr and std::shared_ptr.

Justin Lebar via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 14 01:03:39 PST 2016


> I worry about accidentally escaping (and then capturing) the raw pointer via a type cast.

Right.  I considered that maybe it would be better if we made it so
that dyn_cast / cast don't work on rvalue references, but then
perfectly legal code like

  unique_ptr<Foo> GetFoo();
  cast<Bar>(GetFoo())->Frob();

wouldn't work.

My main motivation for this patch was that IntrusiveRefCntPtr already
implements simplify_type, and has exactly the problem as shared_ptr,
as far as I can tell.  And since a shared_ptr may have just one owner,
I don't think it is any more or less safe in this respect than
unique_ptr.  Of course two wrongs don't make a right, but consistency
is good.

But maybe we're saying that the right thing to do would be to remove
the simplify_type specialization for IntrusiveRefCntPtr.  We could
make it work only for isa, but that may be an excessive amount of
magic for not a lot of instances.

On Wed, Jan 13, 2016 at 10:47 PM, Justin Bogner <mail at justinbogner.com> wrote:
> Justin Lebar via llvm-commits <llvm-commits at lists.llvm.org> writes:
>> jlebar created this revision.
>> jlebar added a reviewer: echristo.
>> jlebar added a subscriber: llvm-commits.
>>
>> This lets us use these functions without calling 'get()' everywhere.
>
> Making this work for isa<> is really nice, but I'm kind of uncomfortable
> witht the subtlety it adds to cast/dyn_cast/dyn_cast_or_null wrt
> unique_ptr. I worry about accidentally escaping (and then capturing) the
> raw pointer via a type cast.
>
>> http://reviews.llvm.org/D15910
>>
>> Files:
>>   include/llvm/Support/Casting.h
>>   unittests/Support/Casting.cpp
>>
>> Index: unittests/Support/Casting.cpp
>> ===================================================================
>> --- unittests/Support/Casting.cpp
>> +++ unittests/Support/Casting.cpp
>> @@ -165,6 +165,26 @@
>>    EXPECT_NE(F5, null_foo);
>>  }
>>
>> +// We should be able to treat unique_ptr<T> just like T* for the purposes of
>> +// isa, dyn_cast, cast, etc.
>> +TEST(CastingTest, unique_ptr) {
>> +  std::unique_ptr<foo> a(new foo());
>> +  EXPECT_TRUE(isa<foo>(a));
>> +
>> +  std::unique_ptr<bar> b(new bar());
>> +  EXPECT_NE(dyn_cast_or_null<foo>(b), null_foo);
>> +}
>> +
>> +// We should be able to treat shared_ptr<T> just like T* for the purposes of
>> +// isa, dyn_cast, cast, etc.
>> +TEST(CastingTest, shared_ptr) {
>> +  auto a = std::make_shared<foo>();
>> +  EXPECT_TRUE(isa<foo>(a));
>> +
>> +  auto b = std::make_shared<bar>();
>> +  EXPECT_NE(dyn_cast_or_null<foo>(b), null_foo);
>> +}
>> +
>>  // These lines are errors...
>>  //foo *F20 = cast<foo>(B2);  // Yields const foo*
>>  //foo &F21 = cast<foo>(B3);  // Yields const foo&
>> Index: include/llvm/Support/Casting.h
>> ===================================================================
>> --- include/llvm/Support/Casting.h
>> +++ 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 {
>>
>> @@ -47,6 +48,30 @@
>>    }
>>  };
>>
>> +template<class T> struct simplify_type<std::unique_ptr<T>> {
>> +  typedef T* SimpleType;
>> +  static SimpleType getSimplifiedValue(std::unique_ptr<T> &Val) { return Val.get(); }
>> +};
>> +
>> +template<class T> struct simplify_type<const std::unique_ptr<T>> {
>> +  typedef /*const*/ T* SimpleType;
>> +  static SimpleType getSimplifiedValue(const std::unique_ptr<T> &Val) {
>> +    return Val.get();
>> +  }
>> +};
>> +
>> +template<class T> struct simplify_type<std::shared_ptr<T>> {
>> +  typedef T* SimpleType;
>> +  static SimpleType getSimplifiedValue(std::shared_ptr<T> &Val) { return Val.get(); }
>> +};
>> +
>> +template<class T> struct simplify_type<const std::shared_ptr<T>> {
>> +  typedef /*const*/ T* SimpleType;
>> +  static SimpleType getSimplifiedValue(const std::shared_ptr<T> &Val) {
>> +    return Val.get();
>> +  }
>> +};
>> +
>>  // The core of the implementation of isa<X> is here; To and From should be
>>  // the names of classes.  This template can be specialized to customize the
>>  // implementation of isa<> without rewriting it from scratch.
>>


More information about the llvm-commits mailing list