// Part of the Carbon Language project, under the Apache License v2.0 with LLVM // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #ifndef CARBON_TOOLCHAIN_SEM_IR_ENTITY_NAME_H_ #define CARBON_TOOLCHAIN_SEM_IR_ENTITY_NAME_H_ #include "common/hashing.h" #include "common/set.h" #include "toolchain/base/value_store.h" #include "toolchain/sem_ir/clang_decl.h" #include "toolchain/sem_ir/ids.h" namespace Carbon::SemIR { struct EntityName : public Printable { auto Print(llvm::raw_ostream& out) const -> void { out << "{name: " << name_id << ", parent_scope: " << parent_scope_id << ", index: " << bind_index_value << ", is_template: " << is_template << ", clang_decl_id: " << clang_decl_id << "}"; } friend auto CarbonHashtableEq(const EntityName& lhs, const EntityName& rhs) -> bool { // This requires that there are no padding bits in the type. This is upheld // since it holds values all of the same size: each is 32 bits, with one // split into 31 and 1 bits. return std::memcmp(&lhs, &rhs, sizeof(EntityName)) == 0; } // Hashing for EntityName. See common/hashing.h. friend auto CarbonHashValue(const EntityName& value, uint64_t seed) -> HashCode { Hasher hasher(seed); hasher.HashRaw(value); return static_cast(hasher); } // The index of the binding, if this is the name of a symbolic binding, or // `None` otherwise. This is also `None` for a `.Self` symbolic binding, // because such a binding is not assigned an index. auto bind_index() const -> CompileTimeBindIndex { return CompileTimeBindIndex(bind_index_value); } // The name. NameId name_id; // The parent scope. NameScopeId parent_scope_id; // TODO: The following two fields are only meaningful for a symbolic binding. // Consider splitting them off into a separate type so that we don't store // them for other kinds of `EntityName`. // The bind_index() value, unwrapped so it can be stored in a bit-field. int32_t bind_index_value : 31 = CompileTimeBindIndex::None.index; // Whether this binding is a template parameter. bool is_template : 1 = false; // For imported C++ global variable names, the Clang decl to use for mangling. // TODO: Move the mapping between global variables and the clang decl to avoid // paying extra memory when the names are not imported from C++. ClangDeclId clang_decl_id = ClangDeclId::None; }; // Value store for EntityName. In addition to the regular ValueStore // functionality, this can provide optional canonical IDs for EntityNames. struct EntityNameStore : public ValueStore { public: // Adds an entity name for a symbolic binding. auto AddSymbolicBindingName(NameId name_id, NameScopeId parent_scope_id, CompileTimeBindIndex bind_index, bool is_template, ClangDeclId clang_decl_id = ClangDeclId::None) -> EntityNameId { return Add({.name_id = name_id, .parent_scope_id = parent_scope_id, .bind_index_value = bind_index.index, .is_template = is_template, .clang_decl_id = clang_decl_id}); } // Convert an `EntityName` to a canonical ID. All calls to this with // equivalent `EntityName`s will return the same `EntityNameId`. Same as // `MakeCanonical(Add(name))` except that no new `EntityName` is added if we // already have a canonical `EntityNameId` for that name. auto AddCanonical(EntityName name) -> EntityNameId; // Convert an ID to a canonical ID. All calls to this with equivalent // `EntityName`s will return the same `EntityNameId`. auto MakeCanonical(EntityNameId id) -> EntityNameId; private: class KeyContext; Set canonical_ids_; }; class EntityNameStore::KeyContext : public TranslatingKeyContext { public: explicit KeyContext(const EntityNameStore* store) : store_(store) {} // Note that it is safe to return a `const` reference here as the underlying // object's lifetime is provided by the `store_`. auto TranslateKey(EntityNameId id) const -> const EntityName& { return store_->Get(id); } private: const EntityNameStore* store_; }; inline auto EntityNameStore::AddCanonical(EntityName name) -> EntityNameId { return canonical_ids_ .Insert( name, [&] { return Add(name); }, KeyContext(this)) .key(); } inline auto EntityNameStore::MakeCanonical(EntityNameId id) -> EntityNameId { return canonical_ids_.Insert(id, KeyContext(this)).key(); } } // namespace Carbon::SemIR #endif // CARBON_TOOLCHAIN_SEM_IR_ENTITY_NAME_H_