[llvm] [DenseMap] Invalidate iterators on erase (PR #199369)
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Sat May 23 12:04:59 PDT 2026
https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/199369
>From 25a605c2f44a85554819c898d5de81686b30030b Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Mon, 11 May 2026 23:37:36 -0700
Subject: [PATCH 1/2] [DenseMap] Invalidate iterators on erase
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Tighten DenseMap's `erase` contract so that, like `insert` and `grow`,
it invalidates iterators and references obtained before the call.
Under the current tombstone-based deletion this is purely an
LLVM_ENABLE_ABI_BREAKING_CHECKS check — the bucket array is not actually
mutated for other entries — but it surfaces stale-iterator-after-erase
patterns now rather than when DenseMap's deletion scheme changes.
Mirrors the SmallPtrSet change in #96762, which dropped tombstones in
small mode and likewise had `erase` invalidate iterators.
Depends on #198982 and #199365
---
llvm/include/llvm/ADT/DenseMap.h | 2 ++
llvm/unittests/ADT/DenseMapTest.cpp | 20 ++++++++++++++++++++
2 files changed, 22 insertions(+)
diff --git a/llvm/include/llvm/ADT/DenseMap.h b/llvm/include/llvm/ADT/DenseMap.h
index b8b548a31acbc..3dac5f6f1e371 100644
--- a/llvm/include/llvm/ADT/DenseMap.h
+++ b/llvm/include/llvm/ADT/DenseMap.h
@@ -330,6 +330,7 @@ class DenseMapBase : public DebugEpochBase {
if (!TheBucket)
return false; // not in map.
+ incrementEpoch();
TheBucket->getSecond().~ValueT();
TheBucket->getFirst() = KeyInfoT::getTombstoneKey();
decrementNumEntries();
@@ -338,6 +339,7 @@ class DenseMapBase : public DebugEpochBase {
}
void erase(iterator I) {
BucketT *TheBucket = &*I;
+ incrementEpoch();
TheBucket->getSecond().~ValueT();
TheBucket->getFirst() = KeyInfoT::getTombstoneKey();
decrementNumEntries();
diff --git a/llvm/unittests/ADT/DenseMapTest.cpp b/llvm/unittests/ADT/DenseMapTest.cpp
index 553d159d33b1a..27bd2a3ef66d0 100644
--- a/llvm/unittests/ADT/DenseMapTest.cpp
+++ b/llvm/unittests/ADT/DenseMapTest.cpp
@@ -1108,4 +1108,24 @@ TEST(DenseMapCustomTest, ValueDtor) {
EXPECT_EQ(0u, CtorTester::getNumConstructed());
}
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+TEST(DenseMapCustomTest, EraseInvalidatesIterators) {
+ DenseMap<int, int> M;
+ M.try_emplace(1, 10);
+ M.try_emplace(2, 20);
+ auto It = M.find(1);
+ M.erase(2);
+ EXPECT_DEATH((void)It->second, "invalid iterator access!");
+}
+
+TEST(DenseMapCustomTest, EraseIteratorInvalidatesOtherIterators) {
+ DenseMap<int, int> M;
+ M.try_emplace(1, 10);
+ M.try_emplace(2, 20);
+ auto Keep = M.find(1);
+ M.erase(M.find(2));
+ EXPECT_DEATH((void)Keep->second, "invalid iterator access!");
+}
+#endif
+
} // namespace
>From 01889ed0dd9b4dc92d7a1f40fa14b10d170299a1 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sat, 23 May 2026 12:04:50 -0700
Subject: [PATCH 2/2] release note
---
llvm/docs/ReleaseNotes.md | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index fc462fd796229..d413cbf0fe326 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -128,6 +128,11 @@ Makes programs 10x faster by doing Special New Thing.
* ``ConstantFP`` now supports vector types and is the canonical form returned by
``ConstantVector::getSplat(C)`` when ``C`` is a scalar ``ConstantFP``.
+* ``DenseMap`` and ``DenseSet`` ``erase`` now invalidates all iterators and
+ references into the container, not just the iterator for the erased element.
+ Use the new ``remove_if`` member to erase matching elements in a single pass
+ instead of erasing while iterating.
+
### Changes to building LLVM
### Changes to TableGen
More information about the llvm-commits
mailing list