[llvm] [Support] Fix VersionTuple DenseMapInfo conformance (PR #206872)

Daniel Rodríguez Troitiño via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 30 19:23:24 PDT 2026


https://github.com/drodriguez created https://github.com/llvm/llvm-project/pull/206872

In C++ standard library (and many other programming languages standard libraries), if two values are equal, they should return the same hash. This requirement is pretty common so associative containers can quickly find values that might be equal by calculating the hash, and if that requirement is not hold, associative containers might not work as expected.

The documentation of `DenseMapInfo` does not specify the same requirement, as far as I can see, but its usage on `DenseMap` relies on it, or objects that compare equal might end up in different buckets and will not be correctly found.

`DenseMapInfo<VersionTuple>` implementation of `getHashValue` was implementing its own logic for hashing, but delegating to `VersionTuple` for equality. `VersionTuple` equality partially compares its scalar member variables, skipping some boolean member variables, but the `getHashValue` implementation was using those boolean member variables as well, creating different hashes for `VersionTuple` that were considered equal. This divergence was creating problems when `VersionTuple` was used as keys for `DenseMap` in some cases.

`VersionTuple` also implements LLVM Hashing `hash_value`, and the implementation of that matches the equality operator, so switch `getHashValue` to delegate to `hash_value`, the same that `isEqual` delegates to the equality operator to keep the logic synchronized.

Includes a small unit test that verifies that when `isEqual` returns true, the return values of `getHashValue` are the same. This test failed before these changes.

>From 763e707b14f0bce646df6237cdb344e7ea3f4fbf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Rodr=C3=ADguez?= <danielrodriguez at meta.com>
Date: Tue, 30 Jun 2026 19:04:47 -0700
Subject: [PATCH] [Support] Fix VersionTuple DenseMapInfo conformance

In C++ standard library (and many other programming languages standard
libraries), if two values are equal, they should return the same hash. This
requirement is pretty common so associative containers can quickly find values
that might be equal by calculating the hash, and if that requirement is not
hold, associative containers might not work as expected.

The documentation of `DenseMapInfo` does not specify the same
requirement, as far as I can see, but its usage on `DenseMap` relies on
it, or objects that compare equal might end up in different buckets and
will not be correctly found.

`DenseMapInfo<VersionTuple>` implementation of `getHashValue` was implementing its own
logic for hashing, but delegating to `VersionTuple` for equality.
`VersionTuple` equality partially compares its scalar member variables,
skipping some boolean member variables, but the `getHashValue`
implementation was using those boolean member variables as well,
creating different hashes for `VersionTuple` that were considered equal.
This divergence was creating problems when `VersionTuple` was used as
keys for `DenseMap` in some cases.

`VersionTuple` also implements LLVM Hashing `hash_value`, and the
implementation of that matches the equality operator, so switch
`getHashValue` to delegate to `hash_value`, the same that `isEqual`
delegates to the equality operator to keep the logic synchronized.

Includes a small unit test that verifies that when `isEqual` returns
true, the return values of `getHashValue` are the same. This test failed
before these changes.
---
 llvm/include/llvm/Support/VersionTuple.h    | 12 +-----------
 llvm/unittests/Support/VersionTupleTest.cpp | 19 +++++++++++++++++++
 2 files changed, 20 insertions(+), 11 deletions(-)

diff --git a/llvm/include/llvm/Support/VersionTuple.h b/llvm/include/llvm/Support/VersionTuple.h
index cae3a88e7a429..c661fd003d0d0 100644
--- a/llvm/include/llvm/Support/VersionTuple.h
+++ b/llvm/include/llvm/Support/VersionTuple.h
@@ -216,17 +216,7 @@ LLVM_ABI raw_ostream &operator<<(raw_ostream &Out, const VersionTuple &V);
 // Provide DenseMapInfo for version tuples.
 template <> struct DenseMapInfo<VersionTuple> {
   static unsigned getHashValue(const VersionTuple &Value) {
-    unsigned Result = Value.getMajor();
-    if (auto Minor = Value.getMinor())
-      Result = detail::combineHashValue(Result, *Minor);
-    if (auto Subminor = Value.getSubminor())
-      Result = detail::combineHashValue(Result, *Subminor);
-    if (auto Build = Value.getBuild())
-      Result = detail::combineHashValue(Result, *Build);
-    if (auto Subbuild = Value.getSubbuild())
-      Result = detail::combineHashValue(Result, *Subbuild);
-
-    return Result;
+    return hash_value(Value);
   }
 
   static bool isEqual(const VersionTuple &LHS, const VersionTuple &RHS) {
diff --git a/llvm/unittests/Support/VersionTupleTest.cpp b/llvm/unittests/Support/VersionTupleTest.cpp
index 724e365f82360..7514b4b81f7c6 100644
--- a/llvm/unittests/Support/VersionTupleTest.cpp
+++ b/llvm/unittests/Support/VersionTupleTest.cpp
@@ -99,3 +99,22 @@ TEST(VersionTuple, withMajorReplaced) {
   EXPECT_TRUE(ReplacedVersion.getSubbuild().has_value());
   EXPECT_EQ(VersionTuple(7, 11, 12, 2, 8), ReplacedVersion);
 }
+
+TEST(VersionTuple, DenseMapInfo) {
+  VersionTuple VT16(16);
+  VersionTuple VT16_0(16, 0);
+
+  VersionTuple VT17(17);
+  VersionTuple VT17_0(17, 0);
+
+  // In C++, if two objects are equal, their hashes should be equal.
+  // DenseMapInfo relies in the same relation for comparing keys.
+  // If isEqual returns true, getHashValue should return the same value.
+  EXPECT_TRUE(DenseMapInfo<VersionTuple>::isEqual(VT16, VT16_0));
+  EXPECT_EQ(DenseMapInfo<VersionTuple>::getHashValue(VT16),
+            DenseMapInfo<VersionTuple>::getHashValue(VT16_0));
+
+  EXPECT_TRUE(DenseMapInfo<VersionTuple>::isEqual(VT17, VT17_0));
+  EXPECT_EQ(DenseMapInfo<VersionTuple>::getHashValue(VT17),
+            DenseMapInfo<VersionTuple>::getHashValue(VT17_0));
+}



More information about the llvm-commits mailing list