aboutsummaryrefslogtreecommitdiff
path: root/llvm/unittests/ADT/DenseMapTest.cpp
diff options
context:
space:
mode:
authorReid Kleckner <rnk@google.com>2020-02-27 13:11:17 -0800
committerReid Kleckner <rnk@google.com>2020-02-28 14:24:04 -0800
commit53f51da09e4530a193b7c17aece6daace6f6b8f5 (patch)
treea7752fc4776ff0786dc4826a3b450c8030a77901 /llvm/unittests/ADT/DenseMapTest.cpp
parentd3693342708a7196c351b90a01bfcbbd9fbea415 (diff)
downloadllvm-53f51da09e4530a193b7c17aece6daace6f6b8f5.zip
llvm-53f51da09e4530a193b7c17aece6daace6f6b8f5.tar.gz
llvm-53f51da09e4530a193b7c17aece6daace6f6b8f5.tar.bz2
[ADT] Allow K to be incomplete during DenseMap<K*, V> instantiation
DenseMap requires two sentinel values for keys: empty and tombstone values. To avoid undefined behavior, LLVM aligns the two sentinel pointers to alignof(T). This requires T to be complete, which is needlessly restrictive. Instead, assume that DenseMap pointer keys have a maximum alignment of 4096, and use the same sentinel values for all pointer keys. The new sentinels are: empty: static_cast<uintptr_t>(-1) << 12 tombstone: static_cast<uintptr_t>(-2) << 12 These correspond to the addresses of -4096 and -8192. Hopefully, such a key is never inserted into a DenseMap. I encountered this while looking at making clang's SourceManager not require FileManager.h, but it has several maps keyed on classes defined in FileManager.h. FileManager depends on various LLVM FS headers, which cumulatively take ~200ms to parse, and are generally not needed. Reviewed By: hans Differential Revision: https://reviews.llvm.org/D75301
Diffstat (limited to 'llvm/unittests/ADT/DenseMapTest.cpp')
-rw-r--r--llvm/unittests/ADT/DenseMapTest.cpp24
1 files changed, 24 insertions, 0 deletions
diff --git a/llvm/unittests/ADT/DenseMapTest.cpp b/llvm/unittests/ADT/DenseMapTest.cpp
index 1ff12a6..9cd974f 100644
--- a/llvm/unittests/ADT/DenseMapTest.cpp
+++ b/llvm/unittests/ADT/DenseMapTest.cpp
@@ -622,4 +622,28 @@ TEST(DenseMapCustomTest, ConstTest) {
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<IncompleteStruct *, int> Map;
+ int Keys[3] = {0, 0, 0};
+ IncompleteStruct *K1 = reinterpret_cast<IncompleteStruct *>(&Keys[0]);
+ IncompleteStruct *K2 = reinterpret_cast<IncompleteStruct *>(&Keys[1]);
+ IncompleteStruct *K3 = reinterpret_cast<IncompleteStruct *>(&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());
+}
}