From 52976c55fbeaa673e18768927a9a230ce869c4ae Mon Sep 17 00:00:00 2001 From: Boaz Brickner Date: Fri, 18 Jul 2025 14:01:27 -0400 Subject: [PATCH] When importing a declaration, first collect all dependent unimported declarations and import them first (#5821) This fixes some tests since we now handle record name scopes correctly. Part of #5533. --- toolchain/check/import_cpp.cpp | 248 ++++++++++++------ .../interop/cpp/function/class.carbon | 60 +++-- .../interop/cpp/function/struct.carbon | 60 +++-- .../interop/cpp/function/union.carbon | 58 ++-- 4 files changed, 275 insertions(+), 151 deletions(-) diff --git a/toolchain/check/import_cpp.cpp b/toolchain/check/import_cpp.cpp index 48e6b0807527..847b61b91fcd 100644 --- a/toolchain/check/import_cpp.cpp +++ b/toolchain/check/import_cpp.cpp @@ -17,11 +17,13 @@ #include "clang/Frontend/TextDiagnostic.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Sema/Lookup.h" +#include "common/check.h" #include "common/ostream.h" #include "common/raw_string_ostream.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/raw_ostream.h" +#include "toolchain/base/kind_switch.h" #include "toolchain/check/class.h" #include "toolchain/check/context.h" #include "toolchain/check/convert.h" @@ -368,11 +370,17 @@ static auto ClangLookup(Context& context, SemIR::NameScopeId scope_id, return lookup; } +// Returns whether `decl` already mapped to an instruction. +static auto IsClangDeclImported(const Context& context, clang::Decl* decl) + -> bool { + return context.sem_ir().clang_decls().Lookup(decl).has_value(); +} + // If `decl` already mapped to an instruction, returns that instruction. // Otherwise returns `None`. -static auto LookupClangDeclInstId(Context& context, clang::Decl* decl) +static auto LookupClangDeclInstId(const Context& context, clang::Decl* decl) -> SemIR::InstId { - auto& clang_decls = context.sem_ir().clang_decls(); + const auto& clang_decls = context.sem_ir().clang_decls(); if (auto context_clang_decl_id = clang_decls.Lookup(decl); context_clang_decl_id.has_value()) { return clang_decls.Get(context_clang_decl_id).inst_id; @@ -380,17 +388,57 @@ static auto LookupClangDeclInstId(Context& context, clang::Decl* decl) return SemIR::InstId::None; } +// Returns the parent of the given declaration. Skips declaration types we +// ignore. +static auto GetParentDecl(clang::Decl* clang_decl) -> clang::Decl* { + clang::DeclContext* decl_context = clang_decl->getDeclContext(); + while (llvm::isa(decl_context)) { + decl_context = decl_context->getParent(); + } + return llvm::cast(decl_context); +} + +// Returns the given declaration's parent scope. Assumes the parent declaration +// was already imported. +static auto GetParentNameScopeId(Context& context, clang::Decl* clang_decl) + -> SemIR::NameScopeId { + SemIR::InstId parent_inst_id = + LookupClangDeclInstId(context, GetParentDecl(clang_decl)); + CARBON_CHECK(parent_inst_id.has_value()); + + CARBON_KIND_SWITCH(context.insts().Get(parent_inst_id)) { + case CARBON_KIND(SemIR::ClassDecl class_decl): { + return context.classes().Get(class_decl.class_id).scope_id; + } + case CARBON_KIND(SemIR::InterfaceDecl interface_decl): { + return context.interfaces().Get(interface_decl.interface_id).scope_id; + } + case CARBON_KIND(SemIR::Namespace namespace_inst): { + return namespace_inst.name_scope_id; + } + default: { + CARBON_FATAL("Unexpected parent instruction kind"); + } + } +} + // Imports a namespace declaration from Clang to Carbon. If successful, returns // the new Carbon namespace declaration `InstId`. If the declaration was already // imported, returns the mapped instruction. static auto ImportNamespaceDecl(Context& context, - SemIR::NameScopeId parent_scope_id, - SemIR::NameId name_id, clang::NamespaceDecl* clang_decl) -> SemIR::InstId { + // Check if the declaration is already mapped. + if (SemIR::InstId existing_inst_id = + LookupClangDeclInstId(context, clang_decl); + existing_inst_id.has_value()) { + return existing_inst_id; + } auto result = AddImportNamespace( context, GetSingletonType(context, SemIR::NamespaceType::TypeInstId), - name_id, parent_scope_id, /*import_id=*/SemIR::InstId::None); + AddIdentifierName(context, clang_decl->getName()), + GetParentNameScopeId(context, clang_decl), + /*import_id=*/SemIR::InstId::None); context.name_scopes() .Get(result.name_scope_id) .set_clang_decl_context_id(context.sem_ir().clang_decls().Add( @@ -398,54 +446,6 @@ static auto ImportNamespaceDecl(Context& context, return result.inst_id; } -// Maps a C++ declaration context to a Carbon namespace. -static auto AsCarbonNamespace(Context& context, - clang::DeclContext* decl_context) - -> SemIR::InstId { - CARBON_CHECK(decl_context); - // Check if the declaration is already mapped. - // TODO: Try to avoid this check by rotating the loops below so they treat the - // given decl_context the same at its enclosing contexts. - if (SemIR::InstId existing_inst_id = LookupClangDeclInstId( - context, clang::dyn_cast(decl_context)); - existing_inst_id.has_value()) { - return existing_inst_id; - } - - auto& clang_decls = context.sem_ir().clang_decls(); - - // We know we have at least one context to map, add all decl contexts we need - // to map. - llvm::SmallVector decl_contexts; - auto parent_decl_id = SemIR::ClangDeclId::None; - do { - decl_contexts.push_back(decl_context); - decl_context = decl_context->getParent(); - parent_decl_id = - clang_decls.Lookup(clang::dyn_cast(decl_context)); - } while (!parent_decl_id.has_value()); - - // We know the parent of the last decl context is mapped, map the rest. - auto namespace_inst_id = SemIR::InstId::None; - do { - decl_context = decl_contexts.pop_back_val(); - auto parent_inst_id = clang_decls.Get(parent_decl_id).inst_id; - auto parent_namespace = - context.insts().GetAs(parent_inst_id); - namespace_inst_id = ImportNamespaceDecl( - context, parent_namespace.name_scope_id, - AddIdentifierName( - context, llvm::dyn_cast(decl_context)->getName()), - clang::dyn_cast(decl_context)); - parent_decl_id = clang_decls.Add({ - .decl = clang::dyn_cast(decl_context), - .inst_id = namespace_inst_id, - }); - } while (!decl_contexts.empty()); - - return namespace_inst_id; -} - // Creates a class declaration for the given class name in the given scope. // Returns the `InstId` for the declaration. static auto BuildClassDecl(Context& context, SemIR::NameScopeId parent_scope_id, @@ -605,23 +605,11 @@ static auto MapRecordType(Context& context, SemIR::LocId loc_id, // Check if the declaration is already mapped. SemIR::InstId record_inst_id = LookupClangDeclInstId(context, record_decl); if (!record_inst_id.has_value()) { - clang::DeclContext* decl_context = record_decl->getDeclContext(); - if (!clang::isa(decl_context) && - !clang::isa(decl_context)) { - context.TODO(loc_id, - "Unsupported mapping of a C++ record to a type within a " - "declaration context that is not the translation unit or " - "a namespace"); - return {.inst_id = SemIR::ErrorInst::TypeInstId, - .type_id = SemIR::ErrorInst::TypeId}; - } - auto parent_inst_id = AsCarbonNamespace(context, decl_context); - auto parent_name_scope_id = - context.insts().GetAs(parent_inst_id).name_scope_id; SemIR::NameId record_name_id = AddIdentifierName(context, record_decl->getName()); - record_inst_id = ImportCXXRecordDecl(context, loc_id, parent_name_scope_id, - record_name_id, record_decl); + record_inst_id = ImportCXXRecordDecl( + context, loc_id, GetParentNameScopeId(context, record_decl), + record_name_id, record_decl); } SemIR::TypeInstId record_type_inst_id = context.types().GetAsTypeInstId(record_inst_id); @@ -971,8 +959,6 @@ static auto CreateFunctionParamsInsts(Context& context, SemIR::LocId loc_id, // the new Carbon function declaration `InstId`. If the declaration was already // imported, returns the mapped instruction. static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id, - SemIR::NameScopeId scope_id, - SemIR::NameId name_id, clang::FunctionDecl* clang_decl) -> SemIR::InstId { // Check if the declaration is already mapped. @@ -1017,8 +1003,8 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id, context.imports().push_back(decl_id); auto function_info = SemIR::Function{ - {.name_id = name_id, - .parent_scope_id = scope_id, + {.name_id = AddIdentifierName(context, clang_decl->getName()), + .parent_scope_id = GetParentNameScopeId(context, clang_decl), .generic_id = SemIR::GenericId::None, .first_param_node_id = Parse::NodeId::None, .last_param_node_id = Parse::NodeId::None, @@ -1048,22 +1034,88 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id, return decl_id; } -// Imports a declaration from Clang to Carbon. If successful, returns the -// instruction for the new Carbon declaration. -// TODO: Remove `scope_id` parameter since we the scope the name was found in -// isn't necessarily the parent scope. See -// https://github.com/carbon-language/carbon-lang/pull/5789/files/a5629ebb303c5b1aef46181eb860b7065ca1aaf1#r2201769611 -static auto ImportNameDecl(Context& context, SemIR::LocId loc_id, - SemIR::NameScopeId scope_id, SemIR::NameId name_id, - clang::NamedDecl* clang_decl) -> SemIR::InstId { + +// Returns all decls that need to be imported before importing the given type. +static auto GetDependentUnimportedTypeDecls(const Context& context, + clang::QualType type) + -> llvm::SmallVector { + while (true) { + type = type.getCanonicalType(); + if (type->isPointerType() || type->isReferenceType()) { + type = type->getPointeeType(); + } else if (const clang::ArrayType* array_type = + type->getAsArrayTypeUnsafe()) { + type = array_type->getElementType(); + } else { + break; + } + } + + type = type.getUnqualifiedType(); + + if (const auto* record_type = type->getAs()) { + if (auto* record_decl = + clang::dyn_cast(record_type->getDecl())) { + if (!IsClangDeclImported(context, record_decl)) { + return {record_decl}; + } + } + } + + return {}; +} + +// Returns all decls that need to be imported before importing the given +// function. +static auto GetDependentUnimportedFunctionDecls( + const Context& context, const clang::FunctionDecl& clang_decl) + -> llvm::SmallVector { + llvm::SmallVector decls; + for (const auto* param : clang_decl.parameters()) { + llvm::append_range( + decls, GetDependentUnimportedTypeDecls(context, param->getType())); + } + llvm::append_range(decls, GetDependentUnimportedTypeDecls( + context, clang_decl.getReturnType())); + return decls; +} + +// Returns all decls that need to be imported before importing the given +// declaration. +static auto GetDependentUnimportedDecls(const Context& context, + clang::Decl* clang_decl) + -> llvm::SmallVector { + llvm::SmallVector decls; + if (auto* parent_decl = GetParentDecl(clang_decl); + !IsClangDeclImported(context, parent_decl)) { + decls.push_back(parent_decl); + } + if (auto* clang_function_decl = clang_decl->getAsFunction()) { - return ImportFunctionDecl(context, loc_id, scope_id, name_id, - clang_function_decl); + llvm::append_range(decls, GetDependentUnimportedFunctionDecls( + context, *clang_function_decl)); + } else if (auto* type_decl = clang::dyn_cast(clang_decl)) { + llvm::append_range( + decls, + GetDependentUnimportedTypeDecls( + context, type_decl->getASTContext().getTypeDeclType(type_decl))); + } + + return decls; +} + +// Imports a declaration from Clang to Carbon. If successful, returns the +// instruction for the new Carbon declaration. Assumes all dependencies have +// already been imported. +static auto ImportDeclAfterDependencies(Context& context, SemIR::LocId loc_id, + clang::Decl* clang_decl) + -> SemIR::InstId { + if (auto* clang_function_decl = clang_decl->getAsFunction()) { + return ImportFunctionDecl(context, loc_id, clang_function_decl); } if (auto* clang_namespace_decl = clang::dyn_cast(clang_decl)) { - return AsCarbonNamespace( - context, llvm::dyn_cast(clang_namespace_decl)); + return ImportNamespaceDecl(context, clang_namespace_decl); } if (auto* type_decl = clang::dyn_cast(clang_decl)) { auto type = type_decl->getASTContext().getTypeDeclType(type_decl); @@ -1082,6 +1134,32 @@ static auto ImportNameDecl(Context& context, SemIR::LocId loc_id, return SemIR::InstId::None; } +// Imports a declaration from Clang to Carbon. If successful, returns the +// instruction for the new Carbon declaration. All unimported dependencies would +// be imported first. +static auto ImportDeclAndDependencies(Context& context, SemIR::LocId loc_id, + clang::Decl* clang_decl) + -> SemIR::InstId { + // Collect dependencies. + llvm::SetVector clang_decls; + clang_decls.insert(clang_decl); + for (size_t i = 0; i < clang_decls.size(); ++i) { + auto dependent_decls = GetDependentUnimportedDecls(context, clang_decls[i]); + for (clang::Decl* dependent_decl : dependent_decls) { + clang_decls.insert(dependent_decl); + } + } + + // Import dependencies in reverse order. + auto inst_id = SemIR::InstId::None; + do { + inst_id = ImportDeclAfterDependencies(context, loc_id, + clang_decls.pop_back_val()); + } while (inst_id.has_value() && !clang_decls.empty()); + + return inst_id; +} + // Imports a `clang::NamedDecl` into Carbon and adds that name into the // `NameScope`. static auto ImportNameDeclIntoScope(Context& context, SemIR::LocId loc_id, @@ -1090,7 +1168,7 @@ static auto ImportNameDeclIntoScope(Context& context, SemIR::LocId loc_id, clang::NamedDecl* clang_decl) -> SemIR::InstId { SemIR::InstId inst_id = - ImportNameDecl(context, loc_id, scope_id, name_id, clang_decl); + ImportDeclAndDependencies(context, loc_id, clang_decl); AddNameToScope(context, scope_id, name_id, inst_id); return inst_id; } diff --git a/toolchain/check/testdata/interop/cpp/function/class.carbon b/toolchain/check/testdata/interop/cpp/function/class.carbon index dbd9e7dd828e..344a74e7df50 100644 --- a/toolchain/check/testdata/interop/cpp/function/class.carbon +++ b/toolchain/check/testdata/interop/cpp/function/class.carbon @@ -224,7 +224,7 @@ class O { auto foo(O::C) -> void; -// --- fail_todo_import_definition_in_outer_definition.carbon +// --- import_definition_in_outer_definition.carbon library "[[@TEST_NAME]]"; @@ -232,13 +232,6 @@ import Cpp library "definition_in_outer_definition.h"; fn F() { //@dump-sem-ir-begin - // CHECK:STDERR: fail_todo_import_definition_in_outer_definition.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported mapping of a C++ record to a type within a declaration context that is not the translation unit or a namespace` [SemanticsTodo] - // CHECK:STDERR: Cpp.foo({}); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: fail_todo_import_definition_in_outer_definition.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] - // CHECK:STDERR: Cpp.foo({}); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: Cpp.foo({}); var x: Cpp.O; //@dump-sem-ir-end @@ -462,6 +455,7 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () // CHECK:STDOUT: %.loc8_12.2: ref %C = temporary_storage @@ -507,6 +501,7 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () // CHECK:STDOUT: %.loc8_12.2: ref %C = temporary_storage @@ -552,6 +547,7 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () // CHECK:STDOUT: %.loc8_12.2: ref %C = temporary_storage @@ -604,6 +600,7 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () // CHECK:STDOUT: %.loc8_12.2: ref %C = temporary_storage @@ -670,6 +667,7 @@ fn F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %N1.ref: = name_ref N1, imports.%N1 [concrete = imports.%N1] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_15.1: %empty_struct_type = struct_literal () // CHECK:STDOUT: %.loc8_15.2: ref %C = temporary_storage @@ -686,18 +684,23 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_definition_in_outer_definition.carbon +// CHECK:STDOUT: --- import_definition_in_outer_definition.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %O: type = class_type @O [concrete] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %C: type = class_type @C [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] -// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] -// CHECK:STDOUT: %O: type = class_type @O [concrete] +// CHECK:STDOUT: %C.val: %C = struct_value () [concrete] // CHECK:STDOUT: %pattern_type.cff: type = pattern_type %O [concrete] // CHECK:STDOUT: %Op.type.1b8: type = fn_type @Op.2, @Destroy.impl(%O) [concrete] // CHECK:STDOUT: %Op.2df: %Op.type.1b8 = struct_value () [concrete] // CHECK:STDOUT: %ptr.820: type = ptr_type %O [concrete] +// CHECK:STDOUT: %Op.type.ac8: type = fn_type @Op.2, @Destroy.impl(%C) [concrete] +// CHECK:STDOUT: %Op.362: %Op.type.ac8 = struct_value () [concrete] +// CHECK:STDOUT: %ptr.de2: type = ptr_type %C [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -706,36 +709,46 @@ fn F() { // CHECK:STDOUT: .O = %O.decl // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } +// CHECK:STDOUT: %O.decl: type = class_decl @O [concrete = constants.%O] {} {} // CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { // CHECK:STDOUT: // CHECK:STDOUT: } { // CHECK:STDOUT: // CHECK:STDOUT: } -// CHECK:STDOUT: %O.decl: type = class_decl @O [concrete = constants.%O] {} {} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %Cpp.ref.loc15: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] -// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal () -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() +// CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc8_12.2: ref %C = temporary_storage +// CHECK:STDOUT: %.loc8_12.3: init %C = class_init (), %.loc8_12.2 [concrete = constants.%C.val] +// CHECK:STDOUT: %.loc8_12.4: ref %C = temporary %.loc8_12.2, %.loc8_12.3 +// CHECK:STDOUT: %.loc8_12.5: ref %C = converted %.loc8_12.1, %.loc8_12.4 +// CHECK:STDOUT: %.loc8_12.6: %C = bind_value %.loc8_12.5 +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_12.6) // CHECK:STDOUT: name_binding_decl { // CHECK:STDOUT: %x.patt: %pattern_type.cff = binding_pattern x [concrete] // CHECK:STDOUT: %x.var_patt: %pattern_type.cff = var_pattern %x.patt [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: %x.var: ref %O = var %x.var_patt -// CHECK:STDOUT: %.loc16: type = splice_block %O.ref [concrete = constants.%O] { -// CHECK:STDOUT: %Cpp.ref.loc16: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: +// CHECK:STDOUT: %.loc9: type = splice_block %O.ref [concrete = constants.%O] { +// CHECK:STDOUT: %Cpp.ref.loc9: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %O.ref: type = name_ref O, imports.%O.decl [concrete = constants.%O] // CHECK:STDOUT: } // CHECK:STDOUT: %x: ref %O = bind_name x, %x.var -// CHECK:STDOUT: %Op.bound: = bound_method %x.var, constants.%Op.2df +// CHECK:STDOUT: %Op.bound.loc9: = bound_method %x.var, constants.%Op.2df // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %x.var, %Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.820 = addr_of %x.var -// CHECK:STDOUT: %no_op: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: %bound_method.loc9: = bound_method %x.var, %Op.specific_fn.1 +// CHECK:STDOUT: %addr.loc9: %ptr.820 = addr_of %x.var +// CHECK:STDOUT: %no_op.loc9: init %empty_tuple.type = call %bound_method.loc9(%addr.loc9) +// CHECK:STDOUT: %Op.bound.loc8: = bound_method %.loc8_12.2, constants.%Op.362 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8: = bound_method %.loc8_12.2, %Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc8: %ptr.de2 = addr_of %.loc8_12.2 +// CHECK:STDOUT: %no_op.loc8: init %empty_tuple.type = call %bound_method.loc8(%addr.loc8) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -828,6 +841,7 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () // CHECK:STDOUT: %.loc8_12.2: ref %C = temporary_storage @@ -938,6 +952,7 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_11.1: ref %C = temporary_storage // CHECK:STDOUT: %foo.call: init %C = call %foo.ref() to %.loc8_11.1 @@ -1001,6 +1016,7 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %foo.call: init %ptr = call %foo.ref() // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/function/struct.carbon b/toolchain/check/testdata/interop/cpp/function/struct.carbon index e35e2f0a8bb8..da3b6734ec8c 100644 --- a/toolchain/check/testdata/interop/cpp/function/struct.carbon +++ b/toolchain/check/testdata/interop/cpp/function/struct.carbon @@ -223,7 +223,7 @@ struct O { auto foo(O::S) -> void; -// --- fail_todo_import_definition_in_outer_definition.carbon +// --- import_definition_in_outer_definition.carbon library "[[@TEST_NAME]]"; @@ -231,13 +231,6 @@ import Cpp library "definition_in_outer_definition.h"; fn F() { //@dump-sem-ir-begin - // CHECK:STDERR: fail_todo_import_definition_in_outer_definition.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported mapping of a C++ record to a type within a declaration context that is not the translation unit or a namespace` [SemanticsTodo] - // CHECK:STDERR: Cpp.foo({}); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: fail_todo_import_definition_in_outer_definition.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] - // CHECK:STDERR: Cpp.foo({}); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: Cpp.foo({}); var x: Cpp.O; //@dump-sem-ir-end @@ -461,6 +454,7 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () // CHECK:STDOUT: %.loc8_12.2: ref %S = temporary_storage @@ -506,6 +500,7 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () // CHECK:STDOUT: %.loc8_12.2: ref %S = temporary_storage @@ -551,6 +546,7 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () // CHECK:STDOUT: %.loc8_12.2: ref %S = temporary_storage @@ -603,6 +599,7 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () // CHECK:STDOUT: %.loc8_12.2: ref %S = temporary_storage @@ -669,6 +666,7 @@ fn F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %N1.ref: = name_ref N1, imports.%N1 [concrete = imports.%N1] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_15.1: %empty_struct_type = struct_literal () // CHECK:STDOUT: %.loc8_15.2: ref %S = temporary_storage @@ -685,18 +683,23 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_definition_in_outer_definition.carbon +// CHECK:STDOUT: --- import_definition_in_outer_definition.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %O: type = class_type @O [concrete] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %S: type = class_type @S [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] -// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] -// CHECK:STDOUT: %O: type = class_type @O [concrete] +// CHECK:STDOUT: %S.val: %S = struct_value () [concrete] // CHECK:STDOUT: %pattern_type.cff: type = pattern_type %O [concrete] // CHECK:STDOUT: %Op.type.1b8: type = fn_type @Op.2, @Destroy.impl(%O) [concrete] // CHECK:STDOUT: %Op.2df: %Op.type.1b8 = struct_value () [concrete] // CHECK:STDOUT: %ptr.820: type = ptr_type %O [concrete] +// CHECK:STDOUT: %Op.type.23f: type = fn_type @Op.2, @Destroy.impl(%S) [concrete] +// CHECK:STDOUT: %Op.952: %Op.type.23f = struct_value () [concrete] +// CHECK:STDOUT: %ptr.149: type = ptr_type %S [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -705,36 +708,46 @@ fn F() { // CHECK:STDOUT: .O = %O.decl // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } +// CHECK:STDOUT: %O.decl: type = class_decl @O [concrete = constants.%O] {} {} // CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { // CHECK:STDOUT: // CHECK:STDOUT: } { // CHECK:STDOUT: // CHECK:STDOUT: } -// CHECK:STDOUT: %O.decl: type = class_decl @O [concrete = constants.%O] {} {} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %Cpp.ref.loc15: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] -// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal () -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() +// CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc8_12.2: ref %S = temporary_storage +// CHECK:STDOUT: %.loc8_12.3: init %S = class_init (), %.loc8_12.2 [concrete = constants.%S.val] +// CHECK:STDOUT: %.loc8_12.4: ref %S = temporary %.loc8_12.2, %.loc8_12.3 +// CHECK:STDOUT: %.loc8_12.5: ref %S = converted %.loc8_12.1, %.loc8_12.4 +// CHECK:STDOUT: %.loc8_12.6: %S = bind_value %.loc8_12.5 +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_12.6) // CHECK:STDOUT: name_binding_decl { // CHECK:STDOUT: %x.patt: %pattern_type.cff = binding_pattern x [concrete] // CHECK:STDOUT: %x.var_patt: %pattern_type.cff = var_pattern %x.patt [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: %x.var: ref %O = var %x.var_patt -// CHECK:STDOUT: %.loc16: type = splice_block %O.ref [concrete = constants.%O] { -// CHECK:STDOUT: %Cpp.ref.loc16: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: +// CHECK:STDOUT: %.loc9: type = splice_block %O.ref [concrete = constants.%O] { +// CHECK:STDOUT: %Cpp.ref.loc9: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %O.ref: type = name_ref O, imports.%O.decl [concrete = constants.%O] // CHECK:STDOUT: } // CHECK:STDOUT: %x: ref %O = bind_name x, %x.var -// CHECK:STDOUT: %Op.bound: = bound_method %x.var, constants.%Op.2df +// CHECK:STDOUT: %Op.bound.loc9: = bound_method %x.var, constants.%Op.2df // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %x.var, %Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.820 = addr_of %x.var -// CHECK:STDOUT: %no_op: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: %bound_method.loc9: = bound_method %x.var, %Op.specific_fn.1 +// CHECK:STDOUT: %addr.loc9: %ptr.820 = addr_of %x.var +// CHECK:STDOUT: %no_op.loc9: init %empty_tuple.type = call %bound_method.loc9(%addr.loc9) +// CHECK:STDOUT: %Op.bound.loc8: = bound_method %.loc8_12.2, constants.%Op.952 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8: = bound_method %.loc8_12.2, %Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc8: %ptr.149 = addr_of %.loc8_12.2 +// CHECK:STDOUT: %no_op.loc8: init %empty_tuple.type = call %bound_method.loc8(%addr.loc8) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -827,6 +840,7 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () // CHECK:STDOUT: %.loc8_12.2: ref %S = temporary_storage @@ -937,6 +951,7 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_11.1: ref %S = temporary_storage // CHECK:STDOUT: %foo.call: init %S = call %foo.ref() to %.loc8_11.1 @@ -1000,6 +1015,7 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %foo.call: init %ptr = call %foo.ref() // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/function/union.carbon b/toolchain/check/testdata/interop/cpp/function/union.carbon index a9680f63e687..8bf8833d44cd 100644 --- a/toolchain/check/testdata/interop/cpp/function/union.carbon +++ b/toolchain/check/testdata/interop/cpp/function/union.carbon @@ -240,7 +240,7 @@ union O { auto foo(O::U) -> void; -// --- fail_todo_import_definition_in_outer_definition.carbon +// --- import_definition_in_outer_definition.carbon library "[[@TEST_NAME]]"; @@ -248,13 +248,6 @@ import Cpp library "definition_in_outer_definition.h"; fn F() { //@dump-sem-ir-begin - // CHECK:STDERR: fail_todo_import_definition_in_outer_definition.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported mapping of a C++ record to a type within a declaration context that is not the translation unit or a namespace` [SemanticsTodo] - // CHECK:STDERR: Cpp.foo({}); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: fail_todo_import_definition_in_outer_definition.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] - // CHECK:STDERR: Cpp.foo({}); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: Cpp.foo({}); var x: Cpp.O; //@dump-sem-ir-end @@ -508,6 +501,7 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () // CHECK:STDOUT: %.loc8_12.2: ref %U = temporary_storage @@ -620,6 +614,7 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () // CHECK:STDOUT: %.loc8_12.2: ref %U = temporary_storage @@ -686,6 +681,7 @@ fn F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %N1.ref: = name_ref N1, imports.%N1 [concrete = imports.%N1] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_15.1: %empty_struct_type = struct_literal () // CHECK:STDOUT: %.loc8_15.2: ref %U = temporary_storage @@ -702,18 +698,23 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_definition_in_outer_definition.carbon +// CHECK:STDOUT: --- import_definition_in_outer_definition.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %O: type = class_type @O [concrete] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %U: type = class_type @U [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] -// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] -// CHECK:STDOUT: %O: type = class_type @O [concrete] +// CHECK:STDOUT: %U.val: %U = struct_value () [concrete] // CHECK:STDOUT: %pattern_type.cff: type = pattern_type %O [concrete] // CHECK:STDOUT: %Op.type.1b8: type = fn_type @Op.2, @Destroy.impl(%O) [concrete] // CHECK:STDOUT: %Op.2df: %Op.type.1b8 = struct_value () [concrete] // CHECK:STDOUT: %ptr.820: type = ptr_type %O [concrete] +// CHECK:STDOUT: %Op.type.8f9: type = fn_type @Op.2, @Destroy.impl(%U) [concrete] +// CHECK:STDOUT: %Op.f3b: %Op.type.8f9 = struct_value () [concrete] +// CHECK:STDOUT: %ptr.a6c: type = ptr_type %U [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -722,36 +723,46 @@ fn F() { // CHECK:STDOUT: .O = %O.decl // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } +// CHECK:STDOUT: %O.decl: type = class_decl @O [concrete = constants.%O] {} {} // CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { // CHECK:STDOUT: // CHECK:STDOUT: } { // CHECK:STDOUT: // CHECK:STDOUT: } -// CHECK:STDOUT: %O.decl: type = class_decl @O [concrete = constants.%O] {} {} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %Cpp.ref.loc15: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] -// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal () -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() +// CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc8_12.2: ref %U = temporary_storage +// CHECK:STDOUT: %.loc8_12.3: init %U = class_init (), %.loc8_12.2 [concrete = constants.%U.val] +// CHECK:STDOUT: %.loc8_12.4: ref %U = temporary %.loc8_12.2, %.loc8_12.3 +// CHECK:STDOUT: %.loc8_12.5: ref %U = converted %.loc8_12.1, %.loc8_12.4 +// CHECK:STDOUT: %.loc8_12.6: %U = bind_value %.loc8_12.5 +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_12.6) // CHECK:STDOUT: name_binding_decl { // CHECK:STDOUT: %x.patt: %pattern_type.cff = binding_pattern x [concrete] // CHECK:STDOUT: %x.var_patt: %pattern_type.cff = var_pattern %x.patt [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: %x.var: ref %O = var %x.var_patt -// CHECK:STDOUT: %.loc16: type = splice_block %O.ref [concrete = constants.%O] { -// CHECK:STDOUT: %Cpp.ref.loc16: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: +// CHECK:STDOUT: %.loc9: type = splice_block %O.ref [concrete = constants.%O] { +// CHECK:STDOUT: %Cpp.ref.loc9: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %O.ref: type = name_ref O, imports.%O.decl [concrete = constants.%O] // CHECK:STDOUT: } // CHECK:STDOUT: %x: ref %O = bind_name x, %x.var -// CHECK:STDOUT: %Op.bound: = bound_method %x.var, constants.%Op.2df +// CHECK:STDOUT: %Op.bound.loc9: = bound_method %x.var, constants.%Op.2df // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %x.var, %Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.820 = addr_of %x.var -// CHECK:STDOUT: %no_op: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: %bound_method.loc9: = bound_method %x.var, %Op.specific_fn.1 +// CHECK:STDOUT: %addr.loc9: %ptr.820 = addr_of %x.var +// CHECK:STDOUT: %no_op.loc9: init %empty_tuple.type = call %bound_method.loc9(%addr.loc9) +// CHECK:STDOUT: %Op.bound.loc8: = bound_method %.loc8_12.2, constants.%Op.f3b +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8: = bound_method %.loc8_12.2, %Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc8: %ptr.a6c = addr_of %.loc8_12.2 +// CHECK:STDOUT: %no_op.loc8: init %empty_tuple.type = call %bound_method.loc8(%addr.loc8) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -844,6 +855,7 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () // CHECK:STDOUT: %.loc8_12.2: ref %U = temporary_storage @@ -954,6 +966,7 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_11.1: ref %U = temporary_storage // CHECK:STDOUT: %foo.call: init %U = call %foo.ref() to %.loc8_11.1 @@ -1017,6 +1030,7 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %foo.call: init %ptr = call %foo.ref() // CHECK:STDOUT: