From 5e62791ad2bca31bd9fcda9619a0aa9b3dbc11cd Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Fri, 5 Jun 2026 16:49:34 -0400 Subject: [PATCH] Improve ClangDeclStore ergonomics (#7311) Change `Lookup` by InstId to return a ClangDecl pointer. All callers were immediately calling `Get` anyway, so this makes call sites a little shorter. The other `Lookup` method, by ClangDeclKey, is sometimes called without calling `Get`, so left that as-is, but renamed to `LookupId`. Also add a `decl` method to ClangDecl so that the commonly repeated `clang_decl->key.decl` can be written `clang_decl->decl()`. --- toolchain/check/cpp/call.cpp | 4 ++-- toolchain/check/cpp/constant.cpp | 12 ++++-------- toolchain/check/cpp/constant.h | 2 +- toolchain/check/cpp/export.cpp | 25 ++++++++++--------------- toolchain/check/cpp/generate_ast.cpp | 11 +++++------ toolchain/check/cpp/impl_lookup.cpp | 2 +- toolchain/check/cpp/import.cpp | 18 ++++++++---------- toolchain/check/cpp/operators.cpp | 8 +++----- toolchain/check/cpp/thunk.cpp | 17 +++++++---------- toolchain/check/eval.cpp | 9 +++------ toolchain/lower/file_context.cpp | 18 +++++++----------- toolchain/lower/handle_call.cpp | 5 ++--- toolchain/sem_ir/clang_decl.cpp | 12 ++++++------ toolchain/sem_ir/clang_decl.h | 9 ++++++--- toolchain/sem_ir/file.cpp | 2 +- toolchain/sem_ir/mangler.cpp | 11 ++++------- 16 files changed, 70 insertions(+), 95 deletions(-) diff --git a/toolchain/check/cpp/call.cpp b/toolchain/check/cpp/call.cpp index 2c1b82777183..525ddaf570c7 100644 --- a/toolchain/check/cpp/call.cpp +++ b/toolchain/check/cpp/call.cpp @@ -140,7 +140,7 @@ static auto ConvertArgToTemplateArg( context.types().TryGetAs( inst.type_id())) { clang::TemplateName name(cast( - context.clang_decls().Get(template_name_type->decl_id).key.decl)); + context.clang_decls().Get(template_name_type->decl_id).decl())); return clang::TemplateArgumentLoc( context.ast_context(), clang::TemplateArgument(name), /*TemplateKWLoc=*/clang::SourceLocation(), @@ -346,7 +346,7 @@ auto PerformCallToCppTemplateName(Context& context, SemIR::LocId loc_id, llvm::ArrayRef arg_ids) -> SemIR::InstId { auto* template_decl = dyn_cast( - context.clang_decls().Get(template_decl_id).key.decl); + context.clang_decls().Get(template_decl_id).decl()); auto loc = GetCppLocation(context, loc_id); // Form a template argument list for this template. diff --git a/toolchain/check/cpp/constant.cpp b/toolchain/check/cpp/constant.cpp index e560c26c8867..d16f52f9448d 100644 --- a/toolchain/check/cpp/constant.cpp +++ b/toolchain/check/cpp/constant.cpp @@ -219,13 +219,11 @@ static auto ConvertArgToExpr(Context& context, SemIR::InstId arg_inst_id, } auto EvalCppCall(Context& context, SemIR::LocId loc_id, - SemIR::ClangDeclId clang_decl_id, SemIR::InstBlockId args_id) + const SemIR::ClangDecl& clang_decl, SemIR::InstBlockId args_id) -> SemIR::ConstantId { const auto& args = context.inst_blocks().Get(args_id); - auto* decl = context.clang_decls().Get(clang_decl_id).GetAsKey().decl; - - auto* function_decl = cast(decl); + auto* function_decl = cast(clang_decl.decl()); // Create expr for the function declaration. auto* decl_ref_expr = clang::DeclRefExpr::Create( @@ -305,10 +303,8 @@ auto MaybeModifyCppThunkCallForConstEval(Context& context, SemIR::Call* call) function_decl = cast( context.clang_decls() - .Get(context.clang_decls().Lookup( - thunk_callee_function.first_decl_id())) - .GetAsKey() - .decl); + .Lookup(thunk_callee_function.first_decl_id()) + ->decl()); if (!(function_decl->isConstexpr() || function_decl->isConsteval())) { return; diff --git a/toolchain/check/cpp/constant.h b/toolchain/check/cpp/constant.h index d4bd7cdfabec..52ad34c4d9e3 100644 --- a/toolchain/check/cpp/constant.h +++ b/toolchain/check/cpp/constant.h @@ -31,7 +31,7 @@ auto EvalCppVarDecl(Context& context, SemIR::LocId loc_id, // Attempt to evaluate a call to a C++ constexpr/consteval function as a // Carbon constant. auto EvalCppCall(Context& context, SemIR::LocId loc_id, - SemIR::ClangDeclId clang_decl_id, SemIR::InstBlockId args_id) + const SemIR::ClangDecl& clang_decl, SemIR::InstBlockId args_id) -> SemIR::ConstantId; // If the callee is a C++ thunk, modify `call` to directly call the diff --git a/toolchain/check/cpp/export.cpp b/toolchain/check/cpp/export.cpp index 3161c8cdc5e1..faed1f9f032e 100644 --- a/toolchain/check/cpp/export.cpp +++ b/toolchain/check/cpp/export.cpp @@ -38,7 +38,7 @@ static auto GetClangDeclContextForScope(Context& context, if (!clang_decl_context_id.has_value()) { return nullptr; } - auto* decl = context.clang_decls().Get(clang_decl_context_id).key.decl; + auto* decl = context.clang_decls().Get(clang_decl_context_id).decl(); return cast(decl); } @@ -137,11 +137,9 @@ auto ExportClassToCpp(Context& context, SemIR::LocId loc_id, // If this class was produced by importing a C++ declaration or has // already been exported to C++, return the corresponding Clang declaration. // That could either be a CXXRecordDecl or an EnumDecl. - if (auto clang_decl_id = - context.clang_decls().Lookup(class_info.first_decl_id()); - clang_decl_id.has_value()) { - return cast( - context.clang_decls().Get(clang_decl_id).key.decl); + if (const auto* clang_decl = + context.clang_decls().Lookup(class_info.first_decl_id())) { + return cast(clang_decl->decl()); } auto* identifier_info = GetClangIdentifierInfo(context, class_info.name_id); @@ -308,12 +306,10 @@ auto ExportFieldToCpp(Context& context, SemIR::InstId field_inst_id, ExportAllFieldsToCpp(context, class_info); // Get the exported `clang::FieldDecl`. - auto clang_decl_id = context.clang_decls().Lookup(field_inst_id); - if (clang_decl_id == SemIR::ClangDeclId::None) { - return nullptr; + if (const auto* clang_decl = context.clang_decls().Lookup(field_inst_id)) { + return cast(clang_decl->decl()); } - return cast( - context.clang_decls().Get(clang_decl_id).key.decl); + return nullptr; } auto CalculateCppFieldOffsets( @@ -957,10 +953,9 @@ auto ExportVarToCpp(Context& context, SemIR::InstId inst_id, // Check if the variable was already exported and return the existing // `VarDecl` if so. Note that the `pattern_id` is used as the key // rather than the `InstId` for the `VarStorage`. - auto clang_decl_id = context.clang_decls().Lookup(var_storage.pattern_id); - if (clang_decl_id.has_value()) { - return cast( - context.clang_decls().Get(clang_decl_id).key.decl); + if (const auto* clang_decl = + context.clang_decls().Lookup(var_storage.pattern_id)) { + return cast(clang_decl->decl()); } // Look up the entity name and check the scope. diff --git a/toolchain/check/cpp/generate_ast.cpp b/toolchain/check/cpp/generate_ast.cpp index c62c85d75d9e..d932b5f23dff 100644 --- a/toolchain/check/cpp/generate_ast.cpp +++ b/toolchain/check/cpp/generate_ast.cpp @@ -447,10 +447,9 @@ auto CarbonExternalASTSource::GetOrExportFunctionToCpp( SemIR::InstId target_inst_id, SemIR::FunctionId function_id) -> clang::FunctionDecl* { SemIR::Function& function = context_->functions().Get(function_id); - auto clang_decl_id = context_->clang_decls().Lookup(function.first_decl_id()); - if (clang_decl_id.has_value()) { - return cast( - context_->clang_decls().Get(clang_decl_id).key.decl); + if (const auto* clang_decl = + context_->clang_decls().Lookup(function.first_decl_id())) { + return cast(clang_decl->decl()); } auto* clang_function_decl = @@ -510,7 +509,7 @@ auto CarbonExternalASTSource::FindExternalVisibleDeclsByName( auto* decl = cast( const_cast(decl_context->getPrimaryContext())); auto key = SemIR::ClangDeclKey::ForNonFunctionDecl(decl); - auto decl_id = context_->clang_decls().Lookup(key); + auto decl_id = context_->clang_decls().LookupId(key); CARBON_CHECK( decl_id.has_value(), "The DeclContext should already be associated with a Carbon InstId."); @@ -591,7 +590,7 @@ static auto GetAsCarbonOwnedClass(Context& context, auto key = SemIR::ClangDeclKey::ForNonFunctionDecl( const_cast(tag_decl->getFirstDecl())); - auto clang_decl_id = context.clang_decls().Lookup(key); + auto clang_decl_id = context.clang_decls().LookupId(key); if (!clang_decl_id.has_value()) { return std::nullopt; } diff --git a/toolchain/check/cpp/impl_lookup.cpp b/toolchain/check/cpp/impl_lookup.cpp index 9886e73d0c5d..12e8774143a9 100644 --- a/toolchain/check/cpp/impl_lookup.cpp +++ b/toolchain/check/cpp/impl_lookup.cpp @@ -64,7 +64,7 @@ static auto TypeAsTagDecl(Context& context, return nullptr; } - return dyn_cast(context.clang_decls().Get(decl_id).key.decl); + return dyn_cast(context.clang_decls().Get(decl_id).decl()); } // If the given type is a C++ class type, returns the corresponding class diff --git a/toolchain/check/cpp/import.cpp b/toolchain/check/cpp/import.cpp index e7ef6a266949..81c976422baa 100644 --- a/toolchain/check/cpp/import.cpp +++ b/toolchain/check/cpp/import.cpp @@ -378,7 +378,7 @@ static auto GetDeclContext(Context& context, SemIR::NameScopeId scope_id) auto scope_clang_decl_context_id = context.name_scopes().Get(scope_id).clang_decl_context_id(); return dyn_cast( - context.clang_decls().Get(scope_clang_decl_context_id).key.decl); + context.clang_decls().Get(scope_clang_decl_context_id).decl()); } // Returns true if the given Clang declaration is the implicit injected class @@ -399,8 +399,7 @@ static auto IsDeclInjectedClassName(Context& context, const SemIR::ClangDecl& clang_decl = context.clang_decls().Get( context.name_scopes().Get(scope_id).clang_decl_context_id()); - const auto* scope_record_decl = - cast(clang_decl.key.decl); + const auto* scope_record_decl = cast(clang_decl.decl()); const clang::ASTContext& ast_context = context.ast_context(); CARBON_CHECK(ast_context.getCanonicalTagType(scope_record_decl) == @@ -441,7 +440,7 @@ static auto ClangLookupName(Context& context, SemIR::NameScopeId scope_id, // Returns whether `decl` already mapped to an instruction. static auto IsClangDeclImported(Context& context, SemIR::ClangDeclKey key) -> bool { - return context.clang_decls().Lookup(key).has_value(); + return context.clang_decls().LookupId(key).has_value(); } // If `decl` already mapped to an instruction, returns that instruction. @@ -449,7 +448,7 @@ static auto IsClangDeclImported(Context& context, SemIR::ClangDeclKey key) static auto LookupClangDeclInstId(Context& context, SemIR::ClangDeclKey key) -> SemIR::InstId { const auto& clang_decls = context.clang_decls(); - if (auto context_clang_decl_id = clang_decls.Lookup(key); + if (auto context_clang_decl_id = clang_decls.LookupId(key); context_clang_decl_id.has_value()) { return clang_decls.Get(context_clang_decl_id).inst_id; } @@ -2602,7 +2601,7 @@ auto ImportClassDefinitionForClangDecl(Context& context, CARBON_CHECK(cpp_file); auto* clang_decl = - cast(context.clang_decls().Get(clang_decl_id).key.decl); + cast(context.clang_decls().Get(clang_decl_id).decl()); auto class_inst_id = context.types().GetAsTypeInstId( context.classes().Get(class_id).first_owning_decl_id); @@ -2637,10 +2636,9 @@ auto GetAsClangVarDecl(Context& context, SemIR::InstId inst_id) -> clang::VarDecl* { if (const auto& var_storage = context.insts().TryGetAs(inst_id)) { - auto clang_decl_id = context.clang_decls().Lookup(var_storage->pattern_id); - if (clang_decl_id.has_value()) { - return cast( - context.clang_decls().Get(clang_decl_id).key.decl); + if (const auto* clang_decl = + context.clang_decls().Lookup(var_storage->pattern_id)) { + return cast(clang_decl->decl()); } } diff --git a/toolchain/check/cpp/operators.cpp b/toolchain/check/cpp/operators.cpp index 906ad696d5c9..0ce39d780b39 100644 --- a/toolchain/check/cpp/operators.cpp +++ b/toolchain/check/cpp/operators.cpp @@ -732,12 +732,10 @@ static auto GetAsCppFunctionDecl(Context& context, SemIR::InstId inst_id) if (!function_type) { return nullptr; } - SemIR::ClangDeclId clang_decl_id = context.clang_decls().Lookup( + const auto* clang_decl = context.clang_decls().Lookup( context.functions().Get(function_type->function_id).first_decl_id()); - return clang_decl_id.has_value() - ? dyn_cast( - context.clang_decls().Get(clang_decl_id).key.decl) - : nullptr; + return clang_decl ? dyn_cast(clang_decl->decl()) + : nullptr; } auto IsCppOperatorMethod(Context& context, SemIR::InstId inst_id) -> bool { diff --git a/toolchain/check/cpp/thunk.cpp b/toolchain/check/cpp/thunk.cpp index aaded7295e78..e11f3465c72e 100644 --- a/toolchain/check/cpp/thunk.cpp +++ b/toolchain/check/cpp/thunk.cpp @@ -245,20 +245,19 @@ struct CalleeFunctionInfo { auto IsCppThunkRequired(Context& context, const SemIR::Function& function) -> bool { - auto clang_decl_id = context.clang_decls().Lookup(function.first_decl_id()); - if (!clang_decl_id.has_value()) { + const auto* clang_decl = + context.clang_decls().Lookup(function.first_decl_id()); + if (!clang_decl) { return false; } - const auto& decl_info = context.clang_decls().Get(clang_decl_id); - - if (!decl_info.is_imported) { + if (!clang_decl->is_imported) { return false; } const auto& signature = - context.clang_decl_signatures().Get(decl_info.key.signature_id); - auto* decl = cast(decl_info.key.decl); + context.clang_decl_signatures().Get(clang_decl->key.signature_id); + auto* decl = cast(clang_decl->decl()); if (signature.kind != SemIR::ClangDeclSignature::Normal || signature.num_params != static_cast(decl->getNumNonObjectParams())) { // We require a thunk if the number of parameters we want isn't all of them. @@ -652,9 +651,7 @@ static auto BuildThunkBody(CppContext& cpp_context, clang::Sema& sema, auto BuildCppThunk(Context& context, const SemIR::Function& callee_function) -> clang::FunctionDecl* { auto clang_decl_key = - context.clang_decls() - .Get(context.clang_decls().Lookup(callee_function.first_decl_id())) - .key; + context.clang_decls().Lookup(callee_function.first_decl_id())->key; clang::FunctionDecl* callee_function_decl = clang_decl_key.decl->getAsFunction(); CARBON_CHECK(callee_function_decl); diff --git a/toolchain/check/eval.cpp b/toolchain/check/eval.cpp index 4cf698e80641..5fbc4f09c15b 100644 --- a/toolchain/check/eval.cpp +++ b/toolchain/check/eval.cpp @@ -3452,13 +3452,10 @@ static auto TryEvalCall(EvalContext& outer_eval_context, SemIR::LocId loc_id, const SemIR::Function& function, SemIR::SpecificId specific_id, SemIR::InstBlockId args_id) -> SemIR::ConstantId { - auto clang_decl_id = outer_eval_context.sem_ir().clang_decls().Lookup( + const auto* clang_decl = outer_eval_context.sem_ir().clang_decls().Lookup( function.first_decl_id()); - if (clang_decl_id.has_value() && outer_eval_context.sem_ir() - .clang_decls() - .Get(clang_decl_id) - .is_imported) { - return EvalCppCall(outer_eval_context.context(), loc_id, clang_decl_id, + if (clang_decl && clang_decl->is_imported) { + return EvalCppCall(outer_eval_context.context(), loc_id, *clang_decl, args_id); } else if (function.body_block_ids.empty()) { // TODO: Diagnose this. diff --git a/toolchain/lower/file_context.cpp b/toolchain/lower/file_context.cpp index 252e5620b7a3..ffbe03164b00 100644 --- a/toolchain/lower/file_context.cpp +++ b/toolchain/lower/file_context.cpp @@ -351,15 +351,12 @@ auto FileContext::GetOrCreateLLVMFunction( // decl_id so it doesn't fall out naturally from the handling below) if (function_id != sem_ir().global_ctor_id()) { const auto& function = sem_ir().functions().Get(function_id); - auto clang_decl_id = - sem_ir().clang_decls().Lookup(function.first_decl_id()); - if (clang_decl_id.has_value()) { - const auto& clang_decl = sem_ir().clang_decls().Get(clang_decl_id); - if (clang_decl.is_imported) { + if (const auto* clang_decl = + sem_ir().clang_decls().Lookup(function.first_decl_id())) { + if (clang_decl->is_imported) { CARBON_CHECK(!specific_id.has_value(), "Specific functions cannot have C++ definitions"); - return HandleReferencedCppFunction( - clang_decl.key.decl->getAsFunction()); + return HandleReferencedCppFunction(clang_decl->decl()->getAsFunction()); } } } @@ -720,11 +717,10 @@ auto FileContext::BuildGlobalVariableDecl(SemIR::VarStorage var_storage) // happens when a Carbon variable is exported and used from C++; code // generation for the C++ code may have already created an // llvm::GlobalVariable. - auto clang_decl_id = sem_ir().clang_decls().Lookup(var_storage.pattern_id); - if (clang_decl_id.has_value()) { - auto* decl = sem_ir().clang_decls().Get(clang_decl_id).key.decl; + if (const auto* clang_decl = + sem_ir().clang_decls().Lookup(var_storage.pattern_id)) { auto* constant = cpp_code_generator_->GetAddrOfGlobal( - CreateGlobalDecl(cast(decl)), + CreateGlobalDecl(cast(clang_decl->decl())), /*isForDefinition=*/false); if (constant) { return constant; diff --git a/toolchain/lower/handle_call.cpp b/toolchain/lower/handle_call.cpp index f4775fadf072..21b37af8ae24 100644 --- a/toolchain/lower/handle_call.cpp +++ b/toolchain/lower/handle_call.cpp @@ -637,10 +637,9 @@ static auto HandleVirtualCall(FunctionContext& context, auto* pointer_type = llvm::PointerType::get(context.llvm_context(), /* address space */ 0); llvm::Value* virtual_fn; - auto clang_decl_id = + const auto* clang_decl = context.sem_ir().clang_decls().Lookup(function.first_decl_id()); - if (clang_decl_id.has_value() && - context.sem_ir().clang_decls().Get(clang_decl_id).is_imported) { + if (clang_decl && clang_decl->is_imported) { // Use absolute vtables for clang interop - the itanium vtable contains // function pointers. auto* virtual_function_pointer_address = context.builder().CreateGEP( diff --git a/toolchain/sem_ir/clang_decl.cpp b/toolchain/sem_ir/clang_decl.cpp index eaa443894dc4..8fc830892fe2 100644 --- a/toolchain/sem_ir/clang_decl.cpp +++ b/toolchain/sem_ir/clang_decl.cpp @@ -81,28 +81,28 @@ auto ClangDecl::Print(llvm::raw_ostream& out) const -> void { ClangDeclStore::ClangDeclStore(CheckIRId check_ir_id) : values_(check_ir_id) {} auto ClangDeclStore::Add(ClangDecl value) -> ClangDeclId { - CARBON_CHECK(!isa(value.key.decl)); + CARBON_CHECK(!isa(value.decl())); auto id = values_.Add(value); inst_id_to_clang_decl_id_.Insert(value.inst_id, id); return id; } auto ClangDeclStore::AddVar(ClangDecl value, InstId pattern_id) -> ClangDeclId { - CARBON_CHECK(isa(value.key.decl)); + CARBON_CHECK(isa(value.decl())); auto id = values_.Add(value); inst_id_to_clang_decl_id_.Insert(pattern_id, id); return id; } -auto ClangDeclStore::Lookup(ClangDeclKey key) const -> ClangDeclId { +auto ClangDeclStore::LookupId(ClangDeclKey key) const -> ClangDeclId { return values_.Lookup(key); } -auto ClangDeclStore::Lookup(InstId inst_id) const -> ClangDeclId { +auto ClangDeclStore::Lookup(InstId inst_id) const -> const ClangDecl* { if (auto result = inst_id_to_clang_decl_id_.Lookup(inst_id)) { - return result.value(); + return &Get(result.value()); } - return ClangDeclId::None; + return nullptr; } auto ClangDeclStore::OutputYaml() const -> Yaml::OutputMapping { diff --git a/toolchain/sem_ir/clang_decl.h b/toolchain/sem_ir/clang_decl.h index 29fa6a5835ba..f65d33390ea4 100644 --- a/toolchain/sem_ir/clang_decl.h +++ b/toolchain/sem_ir/clang_decl.h @@ -184,6 +184,9 @@ struct ClangDecl : public Printable { // created by exporting some Carbon declaration to C++. bool is_imported = false; + // Get the `clang::Decl` pointer. + auto decl() const -> clang::Decl* { return key.decl; } + auto GetAsKey() const -> ClangDeclKey { return key; } }; @@ -212,10 +215,10 @@ class ClangDeclStore { auto Get(ClangDeclId id) const -> const ClangDecl& { return values_.Get(id); } // Looks up a `ClangDeclId` by `ClangDeclKey`. - auto Lookup(ClangDeclKey key) const -> ClangDeclId; + auto LookupId(ClangDeclKey key) const -> ClangDeclId; - // Looks up a `ClangDeclId` by `InstId`. - auto Lookup(InstId inst_id) const -> ClangDeclId; + // Looks up a `ClangDecl` by `InstId`. Returns nullptr if not found. + auto Lookup(InstId inst_id) const -> const ClangDecl*; auto OutputYaml() const -> Yaml::OutputMapping; diff --git a/toolchain/sem_ir/file.cpp b/toolchain/sem_ir/file.cpp index 1d00e3c68d4f..55da37679e22 100644 --- a/toolchain/sem_ir/file.cpp +++ b/toolchain/sem_ir/file.cpp @@ -241,7 +241,7 @@ auto File::AppendCppMangledTypeName(ClassId class_id, } // A C++ class's scope always maps to a Clang tag declaration. auto* tag_decl = - clang::cast(clang_decls().Get(clang_decl_id).key.decl); + clang::cast(clang_decls().Get(clang_decl_id).decl()); cpp_file_->mangle_context().mangleCanonicalTypeName( cpp_file_->ast_context().getCanonicalTagType(tag_decl), out); return true; diff --git a/toolchain/sem_ir/mangler.cpp b/toolchain/sem_ir/mangler.cpp index 1058ecd69bc6..b38643022cf6 100644 --- a/toolchain/sem_ir/mangler.cpp +++ b/toolchain/sem_ir/mangler.cpp @@ -193,10 +193,9 @@ auto Mangler::Mangle(SemIR::FunctionId function_id, // Clang should emit C++ function declarations for us. if (function_id != sem_ir().global_ctor_id()) { - auto clang_decl_id = + const auto* clang_decl = sem_ir().clang_decls().Lookup(function.first_decl_id()); - CARBON_CHECK(!clang_decl_id.has_value() || - !sem_ir().clang_decls().Get(clang_decl_id).is_imported, + CARBON_CHECK(!clang_decl || !clang_decl->is_imported, "Shouldn't mangle C++ function"); } @@ -276,10 +275,8 @@ auto Mangler::MangleGlobalVariable(SemIR::InstId pattern_id) -> std::string { return std::string(); } - auto clang_decl_id = sem_ir().clang_decls().Lookup(pattern_id); - if (clang_decl_id.has_value()) { - CARBON_CHECK(!sem_ir().clang_decls().Get(clang_decl_id).is_imported, - "Mangling a C++ variable"); + if (const auto* clang_decl = sem_ir().clang_decls().Lookup(pattern_id)) { + CARBON_CHECK(!clang_decl->is_imported, "Mangling a C++ variable"); } RawStringOstream os;