diff --git a/llvm/include/llvm/ADT/DenseMapInfo.h b/llvm/include/llvm/ADT/DenseMapInfo.h --- a/llvm/include/llvm/ADT/DenseMapInfo.h +++ b/llvm/include/llvm/ADT/DenseMapInfo.h @@ -16,7 +16,6 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/PointerLikeTypeTraits.h" #include #include #include @@ -32,18 +31,28 @@ //static bool isEqual(const T &LHS, const T &RHS); }; -// Provide DenseMapInfo for all pointers. +// Provide DenseMapInfo for all pointers. Come up with sentinel pointer values +// that are aligned to alignof(T) bytes, but try to avoid requiring T to be +// complete. This allows clients to instantiate DenseMap with forward +// declared key types. Assume that no pointer key type requires more than 4096 +// bytes of alignment. template struct DenseMapInfo { + // The following should hold, but it would require T to be complete: + // static_assert(alignof(T) <= (1 << Log2MaxAlign), + // "DenseMap does not support pointer keys requiring more than " + // "Log2MaxAlign bits of alignment"); + static constexpr uintptr_t Log2MaxAlign = 12; + static inline T* getEmptyKey() { uintptr_t Val = static_cast(-1); - Val <<= PointerLikeTypeTraits::NumLowBitsAvailable; + Val <<= Log2MaxAlign; return reinterpret_cast(Val); } static inline T* getTombstoneKey() { uintptr_t Val = static_cast(-2); - Val <<= PointerLikeTypeTraits::NumLowBitsAvailable; + Val <<= Log2MaxAlign; return reinterpret_cast(Val); } diff --git a/llvm/unittests/ADT/DenseMapTest.cpp b/llvm/unittests/ADT/DenseMapTest.cpp --- a/llvm/unittests/ADT/DenseMapTest.cpp +++ b/llvm/unittests/ADT/DenseMapTest.cpp @@ -622,4 +622,28 @@ EXPECT_NE(Map.find(B), Map.end()); EXPECT_NE(Map.find(C), Map.end()); } + +struct IncompleteStruct; + +TEST(DenseMapCustomTest, OpaquePointerKey) { + // Test that we can use a pointer to an incomplete type as a DenseMap key. + // This is an important build time optimization, since many classes have + // DenseMap members. + DenseMap Map; + int Keys[3] = {0, 0, 0}; + IncompleteStruct *K1 = reinterpret_cast(&Keys[0]); + IncompleteStruct *K2 = reinterpret_cast(&Keys[1]); + IncompleteStruct *K3 = reinterpret_cast(&Keys[2]); + Map.insert({K1, 1}); + Map.insert({K2, 2}); + Map.insert({K3, 3}); + EXPECT_EQ(Map.count(K1), 1u); + EXPECT_EQ(Map[K1], 1); + EXPECT_EQ(Map[K2], 2); + EXPECT_EQ(Map[K3], 3); + Map.clear(); + EXPECT_EQ(Map.find(K1), Map.end()); + EXPECT_EQ(Map.find(K2), Map.end()); + EXPECT_EQ(Map.find(K3), Map.end()); +} }