[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