Skip to content

Commit 0716756

Browse files
authored
Stop passing a lambda as a non-type template argument. (#6229)
This creates ODR issues, as the "same" value store type in different translation units can end up being treated as different types. In some build configurations, such as `-c dbg` with Clang 19.1, this is currently resulting in link-time errors. Instead, make the customization mechanism for mapping keys to values be a member function on the value type.
1 parent 4fdc085 commit 0716756

File tree

3 files changed

+33
-32
lines changed

3 files changed

+33
-32
lines changed

toolchain/base/canonical_value_store.h

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,9 @@ namespace Carbon {
2020
// `ValueT` represents the type being stored.
2121
//
2222
// `KeyT` can optionally be different from `ValueT`, and if so is used for the
23-
// argument to `Lookup`. It must be valid to use both `KeyT` and `ValueT` as
24-
// lookup types in the underlying `Set`.
25-
template <typename IdT, typename KeyT, typename ValueT = KeyT,
26-
// Parentheses around the lambda to help clang-format.
27-
auto ValueToKeyFn =
28-
([](typename ValueStoreTypes<ValueT>::ConstRefType value) ->
29-
typename ValueStoreTypes<ValueT>::ConstRefType {
30-
return value;
31-
})>
23+
// argument to `Lookup`. In this case, `ValueT` must provide a `GetAsKey` member
24+
// function that returns the corresponding key.
25+
template <typename IdT, typename KeyT, typename ValueT = KeyT>
3226
class CanonicalValueStore {
3327
public:
3428
using KeyType = std::remove_cvref_t<KeyT>;
@@ -79,47 +73,55 @@ class CanonicalValueStore {
7973
private:
8074
class KeyContext;
8175

76+
static auto GetAsKey(ConstRefType value) -> ConstRefType
77+
requires std::same_as<KeyT, ValueT>
78+
{
79+
return value;
80+
}
81+
82+
template <typename T>
83+
static auto GetAsKey(T&& value) -> decltype(value.GetAsKey()) {
84+
return value.GetAsKey();
85+
}
86+
8287
ValueStore<IdT, ValueType> values_;
8388
Set<IdT, /*SmallSize=*/0, KeyContext> set_;
8489
};
8590

86-
template <typename IdT, typename KeyT, typename ValueT, auto ValueToKeyFn>
87-
class CanonicalValueStore<IdT, KeyT, ValueT, ValueToKeyFn>::KeyContext
91+
template <typename IdT, typename KeyT, typename ValueT>
92+
class CanonicalValueStore<IdT, KeyT, ValueT>::KeyContext
8893
: public TranslatingKeyContext<KeyContext> {
8994
public:
9095
explicit KeyContext(const ValueStore<IdT, ValueType>* values)
9196
: values_(values) {}
9297

93-
// Note that it is safe to return a `const` reference here as the underlying
94-
// object's lifetime is provided by the `ValueStore`.
98+
// Note that it is safe to return a reference here as the underlying object's
99+
// lifetime is provided by the `ValueStore`.
95100
auto TranslateKey(IdT id) const
96-
-> llvm::function_traits<decltype(ValueToKeyFn)>::result_t {
97-
return ValueToKeyFn(values_->Get(id));
101+
-> decltype(GetAsKey(std::declval<ConstRefType>())) {
102+
return GetAsKey(values_->Get(id));
98103
}
99104

100105
private:
101106
const ValueStore<IdT, ValueType>* values_;
102107
};
103108

104-
template <typename IdT, typename KeyT, typename ValueT, auto ValueToKeyFn>
105-
auto CanonicalValueStore<IdT, KeyT, ValueT, ValueToKeyFn>::Add(ValueType value)
106-
-> IdT {
109+
template <typename IdT, typename KeyT, typename ValueT>
110+
auto CanonicalValueStore<IdT, KeyT, ValueT>::Add(ValueType value) -> IdT {
107111
auto make_key = [&] { return IdT(values_.Add(std::move(value))); };
108-
return set_.Insert(ValueToKeyFn(value), make_key, KeyContext(&values_)).key();
112+
return set_.Insert(GetAsKey(value), make_key, KeyContext(&values_)).key();
109113
}
110114

111-
template <typename IdT, typename KeyT, typename ValueT, auto ValueToKeyFn>
112-
auto CanonicalValueStore<IdT, KeyT, ValueT, ValueToKeyFn>::Lookup(
113-
KeyType key) const -> IdT {
115+
template <typename IdT, typename KeyT, typename ValueT>
116+
auto CanonicalValueStore<IdT, KeyT, ValueT>::Lookup(KeyType key) const -> IdT {
114117
if (auto result = set_.Lookup(key, KeyContext(&values_))) {
115118
return result.key();
116119
}
117120
return IdT::None;
118121
}
119122

120-
template <typename IdT, typename KeyT, typename ValueT, auto ValueToKeyFn>
121-
auto CanonicalValueStore<IdT, KeyT, ValueT, ValueToKeyFn>::Reserve(size_t size)
122-
-> void {
123+
template <typename IdT, typename KeyT, typename ValueT>
124+
auto CanonicalValueStore<IdT, KeyT, ValueT>::Reserve(size_t size) -> void {
123125
// Compute the resulting new insert count using the size of values -- the
124126
// set doesn't have a fast to compute current size.
125127
if (size > values_.size()) {

toolchain/sem_ir/clang_decl.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ struct ClangDecl : public Printable<ClangDecl> {
9090

9191
// The instruction the Clang declaration is mapped to.
9292
InstId inst_id;
93+
94+
auto GetAsKey() const -> ClangDeclKey { return key; }
9395
};
9496

9597
// The ID of a `ClangDecl`.
@@ -108,10 +110,7 @@ struct ClangDeclId : public IdBase<ClangDeclId> {
108110

109111
// Use the AST node pointer directly when doing `Lookup` to find an ID.
110112
using ClangDeclStore =
111-
CanonicalValueStore<ClangDeclId, ClangDeclKey, ClangDecl,
112-
[](const ClangDecl& value) -> const ClangDeclKey& {
113-
return value.key;
114-
}>;
113+
CanonicalValueStore<ClangDeclId, ClangDeclKey, ClangDecl>;
115114

116115
} // namespace Carbon::SemIR
117116

toolchain/sem_ir/cpp_global_var.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,13 @@ struct CppGlobalVar : public Printable<CppGlobalVar> {
4444
// given key, in order to store it in `CanonicalValueStore` and allow lookup
4545
// by `CppGlobalVarKey`.
4646
ClangDeclId clang_decl_id;
47+
48+
auto GetAsKey() const -> CppGlobalVarKey { return key; }
4749
};
4850

4951
// Use the name of a C++ global variable when doing `Lookup` to find an ID.
5052
using CppGlobalVarStore =
51-
CanonicalValueStore<CppGlobalVarId, CppGlobalVarKey, CppGlobalVar,
52-
[](const CppGlobalVar& value)
53-
-> const CppGlobalVarKey& { return value.key; }>;
53+
CanonicalValueStore<CppGlobalVarId, CppGlobalVarKey, CppGlobalVar>;
5454

5555
} // namespace Carbon::SemIR
5656

0 commit comments

Comments
 (0)