[llvm] [ADT] Restore DenseMapPair deriving from std::pair (NFC) (PR #224232)

Kazu Hirata via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 17 01:35:47 PDT 2026


https://github.com/kazutakahirata created https://github.com/llvm/llvm-project/pull/224232

This patch restores llvm::detail::DenseMapPair to inherit from
std::pair<KeyT, ValueT>.

With commit 53a00b2c105d, we now have:

  template <typename BucketT>
  inline constexpr bool isRelocatableBucket =
      std::is_trivially_copy_constructible_v<BucketT> &&
      std::is_trivially_destructible_v<BucketT>;

Note that DenseMapPair derived from std::pair satisfies this, even when
KeyT and ValueT themselves are std::pairs.  As such, we no longer need
DenseMapPair to hold its own members or provide manual constructors and
extra insert(BucketT) overloads.

A follow-up patch will clean up several workarounds introduced across
the codebase in #221853 to accommodate a DenseMapPair not derived from
std::pair.

Assisted-by: Antigravity


>From d6ca5bf3ccc0100d4383ef60f6259346f018fa6b Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Thu, 17 Sep 2026 00:17:05 -0700
Subject: [PATCH] [ADT] Restore DenseMapPair deriving from std::pair (NFC)

This patch restores llvm::detail::DenseMapPair to inherit from
std::pair<KeyT, ValueT>.

With commit 53a00b2c105d, we now have:

  template <typename BucketT>
  inline constexpr bool isRelocatableBucket =
      std::is_trivially_copy_constructible_v<BucketT> &&
      std::is_trivially_destructible_v<BucketT>;

Note that DenseMapPair derived from std::pair satisfies this, even when
KeyT and ValueT themselves are std::pairs.  As such, we no longer need
DenseMapPair to hold its own members or provide manual constructors and
extra insert(BucketT) overloads.

A follow-up patch will clean up several workarounds introduced across
the codebase in #221853 to accommodate a DenseMapPair not derived from
std::pair.

Assisted-by: Antigravity
---
 llvm/include/llvm/ADT/DenseMap.h    | 62 +++++------------------------
 llvm/unittests/ADT/DenseMapTest.cpp |  2 +-
 2 files changed, 11 insertions(+), 53 deletions(-)

diff --git a/llvm/include/llvm/ADT/DenseMap.h b/llvm/include/llvm/ADT/DenseMap.h
index 56c56c489915e..f165613ceba4d 100644
--- a/llvm/include/llvm/ADT/DenseMap.h
+++ b/llvm/include/llvm/ADT/DenseMap.h
@@ -44,45 +44,17 @@
 namespace llvm {
 
 namespace detail {
-// A bucket holds a key and a value. Don't use std::pair, which has a
-// non-trivial copy assignment, which costs is_trivially_copyable.
-template <typename KeyT, typename ValueT> struct DenseMapPair {
-  using first_type = KeyT;
-  using second_type = ValueT;
-
-  KeyT first;
-  ValueT second;
-
-  DenseMapPair() : first(), second() {}
-  DenseMapPair(const KeyT &Key, const ValueT &Value)
-      : first(Key), second(Value) {}
-  DenseMapPair(KeyT &&Key, ValueT &&Value)
-      : first(std::move(Key)), second(std::move(Value)) {}
-  DenseMapPair(const std::pair<KeyT, ValueT> &P)
-      : first(P.first), second(P.second) {}
-  DenseMapPair(std::pair<KeyT, ValueT> &&P)
-      : first(std::move(P.first)), second(std::move(P.second)) {}
-  template <typename U1, typename U2>
-  DenseMapPair(const DenseMapPair<U1, U2> &P)
-      : first(P.first), second(P.second) {}
-  template <typename U1, typename U2>
-  DenseMapPair(DenseMapPair<U1, U2> &&P)
-      : first(std::move(P.first)), second(std::move(P.second)) {}
-
-  operator std::pair<KeyT, ValueT>() const { return {first, second}; }
-  operator std::pair<const KeyT, ValueT>() const { return {first, second}; }
-
-  friend bool operator==(const DenseMapPair &LHS, const DenseMapPair &RHS) {
-    return LHS.first == RHS.first && LHS.second == RHS.second;
-  }
-  friend bool operator!=(const DenseMapPair &LHS, const DenseMapPair &RHS) {
-    return !(LHS == RHS);
-  }
 
-  KeyT &getFirst() { return first; }
-  const KeyT &getFirst() const { return first; }
-  ValueT &getSecond() { return second; }
-  const ValueT &getSecond() const { return second; }
+// We extend a pair to allow users to override the bucket type with their own
+// implementation without requiring two members.
+template <typename KeyT, typename ValueT>
+struct DenseMapPair : std::pair<KeyT, ValueT> {
+  using std::pair<KeyT, ValueT>::pair;
+
+  KeyT &getFirst() { return std::pair<KeyT, ValueT>::first; }
+  const KeyT &getFirst() const { return std::pair<KeyT, ValueT>::first; }
+  ValueT &getSecond() { return std::pair<KeyT, ValueT>::second; }
+  const ValueT &getSecond() const { return std::pair<KeyT, ValueT>::second; }
 };
 
 } // end namespace detail
@@ -327,20 +299,6 @@ class DenseMapBase : public DebugEpochBase {
     return try_emplace_impl(std::move(KV.first), std::move(KV.second));
   }
 
-  template <
-      typename B = BucketT,
-      typename = std::enable_if_t<!std::is_same_v<B, std::pair<KeyT, ValueT>>>>
-  std::pair<iterator, bool> insert(const BucketT &KV) {
-    return try_emplace_impl(KV.first, KV.second);
-  }
-
-  template <
-      typename B = BucketT,
-      typename = std::enable_if_t<!std::is_same_v<B, std::pair<KeyT, ValueT>>>>
-  std::pair<iterator, bool> insert(BucketT &&KV) {
-    return try_emplace_impl(std::move(KV.first), std::move(KV.second));
-  }
-
   // Inserts key,value pair into the map if the key isn't already in the map.
   // The value is constructed in-place if the key is not in the map, otherwise
   // it is not moved.
diff --git a/llvm/unittests/ADT/DenseMapTest.cpp b/llvm/unittests/ADT/DenseMapTest.cpp
index 79ed6731b872a..10325037a0849 100644
--- a/llvm/unittests/ADT/DenseMapTest.cpp
+++ b/llvm/unittests/ADT/DenseMapTest.cpp
@@ -478,7 +478,7 @@ using IntBucket = detail::DenseMapPair<int, int>;
 using PairBucket =
     detail::DenseMapPair<std::pair<int, int>, std::pair<int, int>>;
 
-static_assert(std::is_trivially_copyable_v<IntBucket>);
+static_assert(!std::is_trivially_copyable_v<IntBucket>);
 static_assert(!std::is_trivially_default_constructible_v<IntBucket>);
 
 // std::pair has a user-provided copy assignment operator.



More information about the llvm-commits mailing list