Index: llvm/include/llvm/ADT/PointerIntPair.h =================================================================== --- llvm/include/llvm/ADT/PointerIntPair.h +++ llvm/include/llvm/ADT/PointerIntPair.h @@ -234,6 +234,12 @@ return PointerIntPair::getFromOpaqueValue(P); } + static inline bool + isNull(const PointerIntPair &P) { + // Handles nested PointerIntPair or PointerUnion types. + return PtrTraits::isNull(P.getPointer()); + } + enum { NumLowBitsAvailable = PtrTraits::NumLowBitsAvailable - IntBits }; }; Index: llvm/include/llvm/ADT/PointerUnion.h =================================================================== --- llvm/include/llvm/ADT/PointerUnion.h +++ llvm/include/llvm/ADT/PointerUnion.h @@ -185,8 +185,9 @@ bool isNull() const { // Convert from the void* to one of the pointer types, to make sure that // we recursively strip off low bits if we have a nested PointerUnion. - return !PointerLikeTypeTraits::getFromVoidPointer( - this->Val.getPointer()); + return PointerLikeTypeTraits::isNull( + PointerLikeTypeTraits::getFromVoidPointer( + this->Val.getPointer())); } explicit operator bool() const { return !isNull(); } @@ -225,9 +226,10 @@ /// it. First *getAddrOfPtr1() { assert(is() && "Val is not the first pointer"); - assert( - get() == this->Val.getPointer() && - "Can't get the address because PointerLikeTypeTraits changes the ptr"); + assert(PointerLikeTypeTraits::getAsVoidPointer(get()) + == this->Val.getPointer() + && "Can't get the address because PointerLikeTypeTraits changes the " + "ptr"); return const_cast( reinterpret_cast(this->Val.getAddrOfPointer())); } Index: llvm/include/llvm/ADT/TinyPtrVector.h =================================================================== --- llvm/include/llvm/ADT/TinyPtrVector.h +++ llvm/include/llvm/ADT/TinyPtrVector.h @@ -32,6 +32,7 @@ using VecTy = SmallVector; using value_type = typename VecTy::value_type; using PtrUnion = PointerUnion; + using EltPtrTraits = PointerLikeTypeTraits; private: PtrUnion Val; @@ -213,7 +214,8 @@ EltTy operator[](unsigned i) const { assert(!Val.isNull() && "can't index into an empty vector"); - if (EltTy V = Val.template dyn_cast()) { + EltTy V = Val.template dyn_cast(); + if (!EltPtrTraits::isNull(V)) { assert(i == 0 && "tinyvector index out of range"); return V; } @@ -225,7 +227,8 @@ EltTy front() const { assert(!empty() && "vector empty"); - if (EltTy V = Val.template dyn_cast()) + EltTy V = Val.template dyn_cast(); + if (!EltPtrTraits::isNull(V)) return V; return Val.template get()->front(); } @@ -238,7 +241,7 @@ } void push_back(EltTy NewVal) { - assert(NewVal && "Can't add a null value"); + assert(!EltPtrTraits::isNull(NewVal) && "Can't add a null value"); // If we have nothing, add something. if (Val.isNull()) { @@ -247,7 +250,8 @@ } // If we have a single value, convert to a vector. - if (EltTy V = Val.template dyn_cast()) { + EltTy V = Val.template dyn_cast(); + if (!EltPtrTraits::isNull(V)) { Val = new VecTy(); Val.template get()->push_back(V); } @@ -313,7 +317,8 @@ return std::prev(end()); } assert(!Val.isNull() && "Null value with non-end insert iterator."); - if (EltTy V = Val.template dyn_cast()) { + EltTy V = Val.template dyn_cast(); + if (!EltPtrTraits::isNull(V)) { assert(I == begin()); Val = Elt; push_back(V); @@ -339,9 +344,12 @@ } Val = new VecTy(); - } else if (EltTy V = Val.template dyn_cast()) { - Val = new VecTy(); - Val.template get()->push_back(V); + } else { + EltTy V = Val.template dyn_cast(); + if (!EltPtrTraits::isNull(V)) { + Val = new VecTy(); + Val.template get()->push_back(V); + } } return Val.template get()->insert(begin() + Offset, From, To); } Index: llvm/include/llvm/Support/PointerLikeTypeTraits.h =================================================================== --- llvm/include/llvm/Support/PointerLikeTypeTraits.h +++ llvm/include/llvm/Support/PointerLikeTypeTraits.h @@ -55,6 +55,7 @@ template struct PointerLikeTypeTraits { static inline void *getAsVoidPointer(T *P) { return P; } static inline T *getFromVoidPointer(void *P) { return static_cast(P); } + static inline bool isNull(T *P) { return !P; } enum { NumLowBitsAvailable = detail::ConstantLog2::value }; }; @@ -62,6 +63,7 @@ template <> struct PointerLikeTypeTraits { static inline void *getAsVoidPointer(void *P) { return P; } static inline void *getFromVoidPointer(void *P) { return P; } + static inline bool isNull(void *P) { return !P; } /// Note, we assume here that void* is related to raw malloc'ed memory and /// that malloc returns objects at least 4-byte aligned. However, this may be @@ -83,6 +85,7 @@ static inline const T getFromVoidPointer(const void *P) { return NonConst::getFromVoidPointer(const_cast(P)); } + static inline bool isNull(const T P) { return NonConst::isNull(P); } enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable }; }; @@ -96,6 +99,9 @@ static inline const T *getFromVoidPointer(const void *P) { return NonConst::getFromVoidPointer(const_cast(P)); } + static inline bool isNull(const T *P) { + return NonConst::isNull(const_cast(P)); + } enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable }; }; @@ -107,6 +113,7 @@ static inline uintptr_t getFromVoidPointer(void *P) { return reinterpret_cast(P); } + static inline bool isNull(const uintptr_t P) { return !P; } // No bits are available! enum { NumLowBitsAvailable = 0 }; }; @@ -131,6 +138,7 @@ static inline FunctionPointerT getFromVoidPointer(void *P) { return reinterpret_cast(P); } + static inline bool isNull(FunctionPointerT P) { return !P; } }; /// Provide a default specialization for function pointers that assumes 4-byte Index: llvm/unittests/ADT/TinyPtrVectorTest.cpp =================================================================== --- llvm/unittests/ADT/TinyPtrVectorTest.cpp +++ llvm/unittests/ADT/TinyPtrVectorTest.cpp @@ -22,12 +22,21 @@ using namespace llvm; namespace { +template struct RemovePointer : std::remove_pointer {}; + +template +struct RemovePointer< + PointerIntPair> { + typedef typename RemovePointer::type type; +}; template class TinyPtrVectorTest : public testing::Test { protected: typedef typename VectorT::value_type PtrT; - typedef typename std::remove_pointer::type ValueT; + typedef typename RemovePointer::type ValueT; + using PtrTraits = PointerLikeTypeTraits; VectorT V; VectorT V2; @@ -37,11 +46,13 @@ TinyPtrVectorTest() { for (size_t i = 0, e = array_lengthof(TestValues); i != e; ++i) - TestPtrs.push_back(&TestValues[i]); + TestPtrs.push_back(PtrT(&TestValues[i])); std::shuffle(TestPtrs.begin(), TestPtrs.end(), std::mt19937{}); } + PtrT makePtr(ValueT *V) { return PtrT(V); } + ArrayRef testArray(size_t N) { return makeArrayRef(&TestPtrs[0], N); } @@ -69,9 +80,9 @@ } }; -typedef ::testing::Types, - TinyPtrVector - > TinyPtrVectorTestTypes; +typedef ::testing::Types, TinyPtrVector, + TinyPtrVector>> + TinyPtrVectorTestTypes; TYPED_TEST_CASE(TinyPtrVectorTest, TinyPtrVectorTestTypes); TYPED_TEST(TinyPtrVectorTest, EmptyTest) { @@ -95,8 +106,8 @@ this->expectValues(this->V, this->testArray(4)); this->V.pop_back(); this->expectValues(this->V, this->testArray(3)); - this->TestPtrs[3] = &this->TestValues[42]; - this->TestPtrs[4] = &this->TestValues[43]; + this->TestPtrs[3] = this->makePtr(&this->TestValues[42]); + this->TestPtrs[4] = this->makePtr(&this->TestValues[43]); this->V.push_back(this->TestPtrs[3]); this->expectValues(this->V, this->testArray(4)); this->V.push_back(this->TestPtrs[4]);