[llvm] 45b4eea - [ADT] Add DebugEpochBase::HandleBase::isComparableWith (#219738)

via llvm-commits llvm-commits at lists.llvm.org
Sat Aug 29 21:04:50 PDT 2026


Author: Kazu Hirata
Date: 2026-08-29T21:04:44-07:00
New Revision: 45b4eea3cdbf1df314776ba95c684dddd7182642

URL: https://github.com/llvm/llvm-project/commit/45b4eea3cdbf1df314776ba95c684dddd7182642
DIFF: https://github.com/llvm/llvm-project/commit/45b4eea3cdbf1df314776ba95c684dddd7182642.diff

LOG: [ADT] Add DebugEpochBase::HandleBase::isComparableWith (#219738)

This patch unifies operator== across hash table iterators with
DebugEpochBase::HandleBase::isComparableWith, performing the following
safety checks:

- LHS is either default-constructed or in sync with its container.

- RHS is likewise either default-constructed or in sync with its
container.

- Both iterators belong to the same container instance and share the
  same state (without intervening mutations).

Assisted-by: Antigravity

Added: 
    

Modified: 
    llvm/include/llvm/ADT/DenseMap.h
    llvm/include/llvm/ADT/EpochTracker.h
    llvm/include/llvm/ADT/FoldingSet.h
    llvm/unittests/ADT/DenseMapTest.cpp
    llvm/unittests/ADT/FoldingSet.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ADT/DenseMap.h b/llvm/include/llvm/ADT/DenseMap.h
index 1480031c8d7da..6d036d4a0729f 100644
--- a/llvm/include/llvm/ADT/DenseMap.h
+++ b/llvm/include/llvm/ADT/DenseMap.h
@@ -1338,12 +1338,7 @@ class DenseMapIterator : DebugEpochBase::HandleBase {
 
   [[nodiscard]] friend bool operator==(const DenseMapIterator &LHS,
                                        const DenseMapIterator &RHS) {
-    assert((!LHS.getEpochAddress() || LHS.isHandleInSync()) &&
-           "handle not in sync!");
-    assert((!RHS.getEpochAddress() || RHS.isHandleInSync()) &&
-           "handle not in sync!");
-    assert(LHS.getEpochAddress() == RHS.getEpochAddress() &&
-           "comparing incomparable iterators!");
+    assert(LHS.isComparableWith(RHS) && "incomparable iterators!");
     return LHS.Ptr == RHS.Ptr;
   }
 

diff  --git a/llvm/include/llvm/ADT/EpochTracker.h b/llvm/include/llvm/ADT/EpochTracker.h
index fc41d6f2c92d2..93c0322b70616 100644
--- a/llvm/include/llvm/ADT/EpochTracker.h
+++ b/llvm/include/llvm/ADT/EpochTracker.h
@@ -71,6 +71,15 @@ class DebugEpochBase {
     /// HandleBase instance.
     bool isHandleInSync() const { return *EpochAddress == EpochAtCreation; }
 
+    /// Returns true if this handle and RHS can be compared. Both must be either
+    /// default-constructed or point into the same container and no mutation
+    /// has occurred since they were created.
+    bool isComparableWith(const HandleBase &RHS) const {
+      return (!EpochAddress || isHandleInSync()) &&
+             (!RHS.EpochAddress || RHS.isHandleInSync()) &&
+             EpochAddress == RHS.EpochAddress;
+    }
+
     /// Returns a pointer to the epoch word stored in the data structure
     /// this handle points into.  Can be used to check if two iterators point
     /// into the same data structure.
@@ -94,6 +103,7 @@ class DebugEpochBase {
     HandleBase() = default;
     explicit HandleBase(const DebugEpochBase *) {}
     bool isHandleInSync() const { return true; }
+    bool isComparableWith(const HandleBase &) const { return true; }
     const void *getEpochAddress() const { return nullptr; }
   };
 };

diff  --git a/llvm/include/llvm/ADT/FoldingSet.h b/llvm/include/llvm/ADT/FoldingSet.h
index c984c00b86fd1..9499aa784b7a0 100644
--- a/llvm/include/llvm/ADT/FoldingSet.h
+++ b/llvm/include/llvm/ADT/FoldingSet.h
@@ -635,7 +635,7 @@ template <class T> class FoldingSetIterator : DebugEpochBase::HandleBase {
   }
 
   bool operator==(const FoldingSetIterator &RHS) const {
-    assert(isHandleInSync() && RHS.isHandleInSync() && "handle not in sync!");
+    assert(isComparableWith(RHS) && "incomparable iterators!");
     return Bucket == RHS.Bucket;
   }
   bool operator!=(const FoldingSetIterator &RHS) const {

diff  --git a/llvm/unittests/ADT/DenseMapTest.cpp b/llvm/unittests/ADT/DenseMapTest.cpp
index 2907a1fefdb03..3932ed8c13b78 100644
--- a/llvm/unittests/ADT/DenseMapTest.cpp
+++ b/llvm/unittests/ADT/DenseMapTest.cpp
@@ -1158,6 +1158,24 @@ TEST(DenseMapCustomTest, EraseInvalidatesIterators) {
   M.erase(M.find(2));
   EXPECT_DEATH((void)It->second, "invalid iterator access");
 }
+
+TEST(DenseMapCustomTest, IteratorComparability) {
+  DenseMap<int, int>::iterator I1, I2;
+  EXPECT_EQ(I1, I2);
+
+  DenseMap<int, int> Map1, Map2;
+  Map1.try_emplace(1, 10);
+  Map2.try_emplace(2, 20);
+  EXPECT_DEATH((void)(Map1.begin() == Map2.begin()), "incomparable iterators");
+}
+
+TEST(DenseMapCustomTest, InsertInvalidatesIteratorComparison) {
+  DenseMap<int, int> Map;
+  Map.try_emplace(1, 10);
+  auto It = Map.begin();
+  Map.try_emplace(2, 20);
+  EXPECT_DEATH((void)(It == Map.end()), "incomparable iterators");
+}
 #endif
 
 } // namespace

diff  --git a/llvm/unittests/ADT/FoldingSet.cpp b/llvm/unittests/ADT/FoldingSet.cpp
index 2556d64bae7a3..1b694e84780d3 100644
--- a/llvm/unittests/ADT/FoldingSet.cpp
+++ b/llvm/unittests/ADT/FoldingSet.cpp
@@ -489,6 +489,25 @@ TEST(FoldingSetTest, MoveInvalidatesIterators) {
   FoldingSet<TrivialPair> Other(std::move(Set));
   EXPECT_DEATH((void)It->Value, "invalid iterator access");
 }
+
+TEST(FoldingSetTest, IteratorComparability) {
+  FoldingSet<TrivialPair> Set1, Set2;
+  TrivialPair T1(1, 1), T2(2, 2);
+  Set1.InsertNode(&T1);
+  Set2.InsertNode(&T2);
+  EXPECT_TRUE(Set1.begin() == Set1.begin());
+  EXPECT_FALSE(Set1.begin() == Set1.end());
+  EXPECT_DEATH((void)(Set1.begin() == Set2.begin()), "incomparable iterators");
+}
+
+TEST(FoldingSetTest, InsertInvalidatesIteratorComparison) {
+  FoldingSet<TrivialPair> Set;
+  TrivialPair T1(1, 1), T2(2, 2);
+  Set.InsertNode(&T1);
+  auto It = Set.begin();
+  Set.InsertNode(&T2);
+  EXPECT_DEATH((void)(It == Set.end()), "incomparable iterators");
+}
 #endif
 
 // The InsertPos token is a hash, not a position, so a rehash cannot stale it.


        


More information about the llvm-commits mailing list