Index: llvm/include/llvm/ADT/PointerUnion.h =================================================================== --- llvm/include/llvm/ADT/PointerUnion.h +++ llvm/include/llvm/ADT/PointerUnion.h @@ -18,6 +18,7 @@ #include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/PointerLikeTypeTraits.h" #include #include @@ -87,6 +88,8 @@ }; } +// forward declaration of CastInfoPointerUnionImpl +template struct CastInfoPointerUnionImpl; /// A discriminated union of two or more pointer types, with the discriminator /// in the low bit of the pointer. /// @@ -122,6 +125,8 @@ using First = TypeAtIndex<0, PTs...>; using Base = typename PointerUnion::PointerUnionMembers; + friend struct CastInfoPointerUnionImpl; + public: PointerUnion() = default; @@ -134,26 +139,23 @@ explicit operator bool() const { return !isNull(); } + // FIXME: Replace the uses of is(), get() and dyn_cast() with + // isa, cast and the llvm::dyn_cast + /// Test if the Union currently holds the type matching T. - template bool is() const { - return this->Val.getInt() == FirstIndexOfType::value; - } + template inline bool is() const { return isa(*this); } /// Returns the value of the specified pointer type. /// /// If the specified pointer type is incorrect, assert. - template T get() const { - assert(is() && "Invalid accessor called"); - return PointerLikeTypeTraits::getFromVoidPointer(this->Val.getPointer()); + template inline T get() const { + assert(isa(*this) && "Invalid accessor called"); + return cast(*this); } /// Returns the current pointer if it is of the specified pointer type, /// otherwise returns null. - template T dyn_cast() const { - if (is()) - return get(); - return T(); - } + template inline T dyn_cast() const { return llvm::dyn_cast(*this); } /// If the union is set to the first pointer type get an address pointing to /// it. @@ -205,6 +207,42 @@ return lhs.getOpaqueValue() < rhs.getOpaqueValue(); } +template struct CastInfoPointerUnionImpl { + using From = PointerUnion; + + template static inline bool isPossible(From &F) { + return F.Val.getInt() == FirstIndexOfType::value; + } + + template static To doCast(From &F) { + assert(isPossible(F) && "cast to an incompatible type !"); + return PointerLikeTypeTraits::getFromVoidPointer(F.Val.getPointer()); + } +}; + +// Specialization of CastInfo for PointerUnion +template +struct CastInfo> + : public NullableValueCastFailed, + public DefaultDoCastIfPossible, + CastInfo>> { + using From = PointerUnion; + using Impl = CastInfoPointerUnionImpl; + + static inline bool isPossible(From &f) { + return Impl::template isPossible(f); + } + + static To doCast(From &f) { + return Impl::template doCast(f); + } +}; + +template +struct CastInfo> + : ConstStrippingForwardingCast, + CastInfo>> {}; + // Teach SmallPtrSet that PointerUnion is "basically a pointer", that has // # low bits available = min(PT1bits,PT2bits)-1. template Index: llvm/unittests/ADT/PointerUnionTest.cpp =================================================================== --- llvm/unittests/ADT/PointerUnionTest.cpp +++ llvm/unittests/ADT/PointerUnionTest.cpp @@ -156,4 +156,120 @@ EXPECT_TRUE((void *)n.getAddrOfPtr1() == (void *)&n); } +TEST_F(PointerUnionTest, NewCastInfra) { + // test isa<> + EXPECT_TRUE(isa(a)); + EXPECT_TRUE(isa(b)); + EXPECT_TRUE(isa(c)); + EXPECT_TRUE(isa(n)); + EXPECT_TRUE(isa(i3)); + EXPECT_TRUE(isa(f3)); + EXPECT_TRUE(isa(l3)); + EXPECT_TRUE(isa(i4)); + EXPECT_TRUE(isa(f4)); + EXPECT_TRUE(isa(l4)); + EXPECT_TRUE(isa(d4)); + EXPECT_TRUE(isa(i4null)); + EXPECT_TRUE(isa(f4null)); + EXPECT_TRUE(isa(l4null)); + EXPECT_TRUE(isa(d4null)); + EXPECT_FALSE(isa(a)); + EXPECT_FALSE(isa(b)); + EXPECT_FALSE(isa(c)); + EXPECT_FALSE(isa(n)); + EXPECT_FALSE(isa(i3)); + EXPECT_FALSE(isa(i3)); + EXPECT_FALSE(isa(f3)); + EXPECT_FALSE(isa(f3)); + EXPECT_FALSE(isa(l3)); + EXPECT_FALSE(isa(l3)); + EXPECT_FALSE(isa(i4)); + EXPECT_FALSE(isa(i4)); + EXPECT_FALSE(isa(i4)); + EXPECT_FALSE(isa(f4)); + EXPECT_FALSE(isa(f4)); + EXPECT_FALSE(isa(f4)); + EXPECT_FALSE(isa(l4)); + EXPECT_FALSE(isa(l4)); + EXPECT_FALSE(isa(l4)); + EXPECT_FALSE(isa(d4)); + EXPECT_FALSE(isa(d4)); + EXPECT_FALSE(isa(d4)); + EXPECT_FALSE(isa(i4null)); + EXPECT_FALSE(isa(i4null)); + EXPECT_FALSE(isa(i4null)); + EXPECT_FALSE(isa(f4null)); + EXPECT_FALSE(isa(f4null)); + EXPECT_FALSE(isa(f4null)); + EXPECT_FALSE(isa(l4null)); + EXPECT_FALSE(isa(l4null)); + EXPECT_FALSE(isa(l4null)); + EXPECT_FALSE(isa(d4null)); + EXPECT_FALSE(isa(d4null)); + EXPECT_FALSE(isa(d4null)); + + // test cast<> + EXPECT_EQ(cast(a), &f); + EXPECT_EQ(cast(b), &i); + EXPECT_EQ(cast(c), &i); + EXPECT_EQ(cast(i3), &i); + EXPECT_EQ(cast(f3), &f); + EXPECT_EQ(cast(l3), &l); + EXPECT_EQ(cast(i4), &i); + EXPECT_EQ(cast(f4), &f); + EXPECT_EQ(cast(l4), &l); + EXPECT_EQ(cast(d4), &d); + + // test dyn_cast + EXPECT_EQ(dyn_cast(a), nullptr); + EXPECT_EQ(dyn_cast(a), &f); + EXPECT_EQ(dyn_cast(b), &i); + EXPECT_EQ(dyn_cast(b), nullptr); + EXPECT_EQ(dyn_cast(c), &i); + EXPECT_EQ(dyn_cast(c), nullptr); + EXPECT_EQ(dyn_cast(n), nullptr); + EXPECT_EQ(dyn_cast(n), nullptr); + EXPECT_EQ(dyn_cast(i3), &i); + EXPECT_EQ(dyn_cast(i3), nullptr); + EXPECT_EQ(dyn_cast(i3), nullptr); + EXPECT_EQ(dyn_cast(f3), nullptr); + EXPECT_EQ(dyn_cast(f3), &f); + EXPECT_EQ(dyn_cast(f3), nullptr); + EXPECT_EQ(dyn_cast(l3), nullptr); + EXPECT_EQ(dyn_cast(l3), nullptr); + EXPECT_EQ(dyn_cast(l3), &l); + EXPECT_EQ(dyn_cast(i4), &i); + EXPECT_EQ(dyn_cast(i4), nullptr); + EXPECT_EQ(dyn_cast(i4), nullptr); + EXPECT_EQ(dyn_cast(i4), nullptr); + EXPECT_EQ(dyn_cast(f4), nullptr); + EXPECT_EQ(dyn_cast(f4), &f); + EXPECT_EQ(dyn_cast(f4), nullptr); + EXPECT_EQ(dyn_cast(f4), nullptr); + EXPECT_EQ(dyn_cast(l4), nullptr); + EXPECT_EQ(dyn_cast(l4), nullptr); + EXPECT_EQ(dyn_cast(l4), &l); + EXPECT_EQ(dyn_cast(l4), nullptr); + EXPECT_EQ(dyn_cast(d4), nullptr); + EXPECT_EQ(dyn_cast(d4), nullptr); + EXPECT_EQ(dyn_cast(d4), nullptr); + EXPECT_EQ(dyn_cast(d4), &d); + EXPECT_EQ(dyn_cast(i4null), nullptr); + EXPECT_EQ(dyn_cast(i4null), nullptr); + EXPECT_EQ(dyn_cast(i4null), nullptr); + EXPECT_EQ(dyn_cast(i4null), nullptr); + EXPECT_EQ(dyn_cast(f4null), nullptr); + EXPECT_EQ(dyn_cast(f4null), nullptr); + EXPECT_EQ(dyn_cast(f4null), nullptr); + EXPECT_EQ(dyn_cast(f4null), nullptr); + EXPECT_EQ(dyn_cast(l4null), nullptr); + EXPECT_EQ(dyn_cast(l4null), nullptr); + EXPECT_EQ(dyn_cast(l4null), nullptr); + EXPECT_EQ(dyn_cast(l4null), nullptr); + EXPECT_EQ(dyn_cast(d4null), nullptr); + EXPECT_EQ(dyn_cast(d4null), nullptr); + EXPECT_EQ(dyn_cast(d4null), nullptr); + EXPECT_EQ(dyn_cast(d4null), nullptr); +} + } // end anonymous namespace