diff --git a/llvm/include/llvm/ADT/PointerIntPair.h b/llvm/include/llvm/ADT/PointerIntPair.h --- a/llvm/include/llvm/ADT/PointerIntPair.h +++ b/llvm/include/llvm/ADT/PointerIntPair.h @@ -19,10 +19,44 @@ #include "llvm/Support/type_traits.h" #include #include +#include #include namespace llvm { +namespace detail { +template struct PunnedPointer { + static_assert(sizeof(Ptr) == sizeof(intptr_t), ""); + + // Asserts that allow us to let the compiler implement the destructor and + // copy/move constructors + static_assert(std::is_trivially_destructible::value, ""); + static_assert(std::is_trivially_copy_constructible::value, ""); + static_assert(std::is_trivially_move_constructible::value, ""); + + explicit constexpr PunnedPointer(intptr_t i = 0) { *this = i; } + + constexpr intptr_t asInt() const { + intptr_t R = 0; + std::memcpy(&R, Data, sizeof(R)); + return R; + } + + constexpr operator intptr_t() const { return asInt(); } + + constexpr PunnedPointer &operator=(intptr_t V) { + std::memcpy(Data, &V, sizeof(Data)); + return *this; + } + + Ptr *getPointerAddress() { return reinterpret_cast(Data); } + const Ptr *getPointerAddress() const { return reinterpret_cast(Data); } + +private: + alignas(Ptr) unsigned char Data[sizeof(Ptr)]; +}; +} // namespace detail + template struct DenseMapInfo; template struct PointerIntPairInfo; @@ -46,7 +80,7 @@ class PointerIntPair { // Used by MSVC visualizer and generally helpful for debugging/visualizing. using InfoTy = Info; - intptr_t Value = 0; + detail::PunnedPointer Value; public: constexpr PointerIntPair() = default; @@ -86,10 +120,12 @@ assert(Value == reinterpret_cast(getPointer()) && "Can only return the address if IntBits is cleared and " "PtrTraits doesn't change the pointer"); - return reinterpret_cast(&Value); + return Value.getPointerAddress(); } - void *getOpaqueValue() const { return reinterpret_cast(Value); } + void *getOpaqueValue() const { + return reinterpret_cast(Value.asInt()); + } void setFromOpaqueValue(void *Val) & { Value = reinterpret_cast(Val); diff --git a/llvm/unittests/ADT/PointerIntPairTest.cpp b/llvm/unittests/ADT/PointerIntPairTest.cpp --- a/llvm/unittests/ADT/PointerIntPairTest.cpp +++ b/llvm/unittests/ADT/PointerIntPairTest.cpp @@ -109,4 +109,22 @@ "trivially copyable"); } +TEST(PointerIntPairTest, TypePunning) { + int I = 0; + int *IntPtr = &I; + + int **IntPtrBegin = &IntPtr; + int **IntPtrEnd = IntPtrBegin + 1; + + PointerIntPair Pair; + int **PairAddr = Pair.getAddrOfPointer(); + + while (IntPtrBegin != IntPtrEnd) { + *PairAddr = *IntPtrBegin; + ++PairAddr; + ++IntPtrBegin; + } + EXPECT_EQ(Pair.getPointer(), IntPtr); +} + } // end anonymous namespace