diff options
author | Zachary Turner <zturner@google.com> | 2017-04-12 19:59:37 +0000 |
---|---|---|
committer | Zachary Turner <zturner@google.com> | 2017-04-12 19:59:37 +0000 |
commit | 2bb94cd0ddfc75b883192845a986ce228d7cd31d (patch) | |
tree | e623a410efef227a255b477de27765e77d96d73e /llvm/unittests/Support | |
parent | 538b3f419835de3147c529c8214a41ad089af777 (diff) | |
download | bcm5719-llvm-2bb94cd0ddfc75b883192845a986ce228d7cd31d.tar.gz bcm5719-llvm-2bb94cd0ddfc75b883192845a986ce228d7cd31d.zip |
[Support] Add support for unique_ptr<> to Casting.h.
Often you have a unique_ptr<T> where T supports LLVM's
casting methods, and you wish to cast it to a unique_ptr<U>.
Prior to this patch, this requires doing hacky things like:
unique_ptr<U> Casted;
if (isa<U>(Orig.get()))
Casted.reset(cast<U>(Orig.release()));
This is overly verbose, and it would be nice to just be able
to use unique_ptr directly with cast and dyn_cast. To this end,
this patch updates cast<> to work directly with unique_ptr<T>,
so you can now write:
auto Casted = cast<U>(std::move(Orig));
Since it's possible for dyn_cast<> to fail, however, we choose
to use a slightly different API here, because it's awkward to
write
if (auto Casted = dyn_cast<U>(std::move(Orig))) {}
when Orig may end up not having been moved at all. So the
interface for dyn_cast is
if (auto Casted = unique_dyn_cast<U>(Orig)) {}
Where the inclusion of `unique` in the name of the cast operator
re-affirms that regardless of success of or fail of the casting,
exactly one of the input value and the return value will contain
a non-null result.
Differential Revision: https://reviews.llvm.org/D31890
llvm-svn: 300098
Diffstat (limited to 'llvm/unittests/Support')
-rw-r--r-- | llvm/unittests/Support/Casting.cpp | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/llvm/unittests/Support/Casting.cpp b/llvm/unittests/Support/Casting.cpp index e6c35fc21eb..9a818f6bdeb 100644 --- a/llvm/unittests/Support/Casting.cpp +++ b/llvm/unittests/Support/Casting.cpp @@ -40,6 +40,14 @@ struct foo { }*/ }; +struct base { + virtual ~base() {} +}; + +struct derived : public base { + static bool classof(const base *B) { return true; } +}; + template <> struct isa_impl<foo, bar> { static inline bool doit(const bar &Val) { dbgs() << "Classof: " << &Val << "\n"; @@ -47,6 +55,10 @@ template <> struct isa_impl<foo, bar> { } }; +template <typename T> struct isa_impl<foo, T> { + static inline bool doit(const T &Val) { return false; } +}; + foo *bar::baz() { return cast<foo>(this); } @@ -123,6 +135,13 @@ TEST(CastingTest, cast) { // EXPECT_EQ(F7, null_foo); foo *F8 = B1.baz(); EXPECT_NE(F8, null_foo); + + std::unique_ptr<const bar> BP(B2); + auto FP = cast<foo>(std::move(BP)); + static_assert(std::is_same<std::unique_ptr<const foo>, decltype(FP)>::value, + "Incorrect deduced return type!"); + EXPECT_NE(FP.get(), null_foo); + FP.release(); } TEST(CastingTest, cast_or_null) { @@ -136,6 +155,10 @@ TEST(CastingTest, cast_or_null) { EXPECT_EQ(F14, null_foo); foo *F15 = B1.caz(); EXPECT_NE(F15, null_foo); + + std::unique_ptr<const bar> BP(fub()); + auto FP = cast_or_null<foo>(std::move(BP)); + EXPECT_EQ(FP.get(), null_foo); } TEST(CastingTest, dyn_cast) { @@ -165,6 +188,58 @@ TEST(CastingTest, dyn_cast_or_null) { EXPECT_NE(F5, null_foo); } +std::unique_ptr<derived> newd() { return llvm::make_unique<derived>(); } +std::unique_ptr<base> newb() { return llvm::make_unique<derived>(); } + +TEST(CastingTest, unique_dyn_cast) { + derived *OrigD = nullptr; + auto D = llvm::make_unique<derived>(); + OrigD = D.get(); + + // Converting from D to itself is valid, it should return a new unique_ptr + // and the old one should become nullptr. + auto NewD = unique_dyn_cast<derived>(D); + ASSERT_EQ(OrigD, NewD.get()); + ASSERT_EQ(nullptr, D); + + // Converting from D to B is valid, B should have a value and D should be + // nullptr. + auto B = unique_dyn_cast<base>(NewD); + ASSERT_EQ(OrigD, B.get()); + ASSERT_EQ(nullptr, NewD); + + // Converting from B to itself is valid, it should return a new unique_ptr + // and the old one should become nullptr. + auto NewB = unique_dyn_cast<base>(B); + ASSERT_EQ(OrigD, NewB.get()); + ASSERT_EQ(nullptr, B); + + // Converting from B to D is valid, D should have a value and B should be + // nullptr; + D = unique_dyn_cast<derived>(NewB); + ASSERT_EQ(OrigD, D.get()); + ASSERT_EQ(nullptr, NewB); + + // Converting between unrelated types should fail. The original value should + // remain unchanged and it should return nullptr. + auto F = unique_dyn_cast<foo>(D); + ASSERT_EQ(nullptr, F); + ASSERT_EQ(OrigD, D.get()); + + // All of the above should also hold for temporaries. + auto D2 = unique_dyn_cast<derived>(newd()); + EXPECT_NE(nullptr, D2); + + auto B2 = unique_dyn_cast<derived>(newb()); + EXPECT_NE(nullptr, B2); + + auto B3 = unique_dyn_cast<base>(newb()); + EXPECT_NE(nullptr, B3); + + auto F2 = unique_dyn_cast<foo>(newb()); + EXPECT_EQ(nullptr, F2); +} + // These lines are errors... //foo *F20 = cast<foo>(B2); // Yields const foo* //foo &F21 = cast<foo>(B3); // Yields const foo& |