[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