[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