diff --git a/toolchain/check/BUILD b/toolchain/check/BUILD index bfeefba008bdc..4d2dcada5584d 100644 --- a/toolchain/check/BUILD +++ b/toolchain/check/BUILD @@ -131,6 +131,7 @@ cc_library( "//toolchain/lex:tokenized_buffer", "//toolchain/parse:node_kind", "//toolchain/parse:tree", + "//toolchain/sem_ir:clang_decl", "//toolchain/sem_ir:expr_info", "//toolchain/sem_ir:file", "//toolchain/sem_ir:formatter", diff --git a/toolchain/check/import_cpp.cpp b/toolchain/check/import_cpp.cpp index a26320aee3461..8142d9454d96a 100644 --- a/toolchain/check/import_cpp.cpp +++ b/toolchain/check/import_cpp.cpp @@ -38,6 +38,7 @@ #include "toolchain/diagnostics/diagnostic_emitter.h" #include "toolchain/diagnostics/format_providers.h" #include "toolchain/parse/node_ids.h" +#include "toolchain/sem_ir/clang_decl.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/name_scope.h" #include "toolchain/sem_ir/typed_insts.h" @@ -462,8 +463,21 @@ static auto ClangLookup(Context& context, SemIR::NameScopeId scope_id, return lookup; } +// If `decl` already mapped to an instruction, returns that instruction. +// Otherwise returns `None`. +static auto LookupClangDeclInstId(Context& context, clang::Decl* decl) + -> SemIR::InstId { + 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; + } + return SemIR::InstId::None; +} + // Imports a namespace declaration from Clang to Carbon. If successful, returns -// the new Carbon namespace declaration `InstId`. +// 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, @@ -484,15 +498,17 @@ static auto AsCarbonNamespace(Context& context, clang::DeclContext* decl_context) -> SemIR::InstId { CARBON_CHECK(decl_context); - auto& clang_decls = context.sem_ir().clang_decls(); - - // Check if the decl context is already mapped to a Carbon namespace. - if (auto context_clang_decl_id = - clang_decls.Lookup(clang::dyn_cast(decl_context)); - context_clang_decl_id.has_value()) { - return clang_decls.Get(context_clang_decl_id).inst_id; + // 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; @@ -681,12 +697,9 @@ static auto MapRecordType(Context& context, SemIR::LocId loc_id, return {.inst_id = SemIR::TypeInstId::None, .type_id = SemIR::TypeId::None}; } - auto& clang_decls = context.sem_ir().clang_decls(); - SemIR::InstId record_inst_id = SemIR::InstId::None; - if (auto record_clang_decl_id = clang_decls.Lookup(record_decl); - record_clang_decl_id.has_value()) { - record_inst_id = clang_decls.Get(record_clang_decl_id).inst_id; - } else { + // Check if the declaration is already mapped. + SemIR::InstId record_inst_id = LookupClangDeclInstId(context, record_decl); + if (!record_inst_id.has_value()) { auto parent_inst_id = AsCarbonNamespace(context, record_decl->getDeclContext()); auto parent_name_scope_id = @@ -1041,12 +1054,20 @@ static auto CreateFunctionParamsInsts(Context& context, SemIR::LocId loc_id, } // Imports a function declaration from Clang to Carbon. If successful, returns -// the new Carbon function declaration `InstId`. +// 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. + if (SemIR::InstId existing_inst_id = + LookupClangDeclInstId(context, clang_decl); + existing_inst_id.has_value()) { + return existing_inst_id; + } + if (clang_decl->isVariadic()) { context.TODO(loc_id, "Unsupported: Variadic function"); MarkFailedDecl(context, clang_decl); @@ -1114,6 +1135,9 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_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 { @@ -1123,8 +1147,8 @@ static auto ImportNameDecl(Context& context, SemIR::LocId loc_id, } if (auto* clang_namespace_decl = clang::dyn_cast(clang_decl)) { - return ImportNamespaceDecl(context, scope_id, name_id, - clang_namespace_decl); + return AsCarbonNamespace( + context, llvm::dyn_cast(clang_namespace_decl)); } if (auto* type_decl = clang::dyn_cast(clang_decl)) { auto type = type_decl->getASTContext().getTypeDeclType(type_decl); diff --git a/toolchain/check/testdata/interop/cpp/class/class.carbon b/toolchain/check/testdata/interop/cpp/class/class.carbon index f9f9356df5ad2..6df643967f68b 100644 --- a/toolchain/check/testdata/interop/cpp/class/class.carbon +++ b/toolchain/check/testdata/interop/cpp/class/class.carbon @@ -576,11 +576,9 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: constants { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] // CHECK:STDOUT: %Bar1: type = class_type @Bar1 [concrete] -// CHECK:STDOUT: %foo1.type.148: type = fn_type @foo1.1 [concrete] -// CHECK:STDOUT: %foo1.8cd: %foo1.type.148 = struct_value () [concrete] +// CHECK:STDOUT: %foo1.type: type = fn_type @foo1 [concrete] +// CHECK:STDOUT: %foo1: %foo1.type = struct_value () [concrete] // CHECK:STDOUT: %Bar2: type = class_type @Bar2 [concrete] -// CHECK:STDOUT: %foo1.type.0b8: type = fn_type @foo1.2 [concrete] -// CHECK:STDOUT: %foo1.ba2: %foo1.type.0b8 = struct_value () [concrete] // CHECK:STDOUT: %foo2.type: type = fn_type @foo2 [concrete] // CHECK:STDOUT: %foo2: %foo2.type = struct_value () [concrete] // CHECK:STDOUT: } @@ -592,9 +590,8 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: %Bar1.decl: type = class_decl @Bar1 [concrete = constants.%Bar1] {} {} -// CHECK:STDOUT: %foo1.decl.c80: %foo1.type.148 = fn_decl @foo1.1 [concrete = constants.%foo1.8cd] {} {} +// CHECK:STDOUT: %foo1.decl: %foo1.type = fn_decl @foo1 [concrete = constants.%foo1] {} {} // CHECK:STDOUT: %Bar2.decl: type = class_decl @Bar2 [concrete = constants.%Bar2] {} {} -// CHECK:STDOUT: %foo1.decl.191: %foo1.type.0b8 = fn_decl @foo1.2 [concrete = constants.%foo1.ba2] {} {} // CHECK:STDOUT: %foo2.decl: %foo2.type = fn_decl @foo2 [concrete = constants.%foo2] {} {} // CHECK:STDOUT: } // CHECK:STDOUT: @@ -603,12 +600,12 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: // CHECK:STDOUT: %Bar1.ref: type = name_ref Bar1, imports.%Bar1.decl [concrete = constants.%Bar1] -// CHECK:STDOUT: %foo1.ref.loc8: %foo1.type.148 = name_ref foo1, imports.%foo1.decl.c80 [concrete = constants.%foo1.8cd] +// CHECK:STDOUT: %foo1.ref.loc8: %foo1.type = name_ref foo1, imports.%foo1.decl [concrete = constants.%foo1] // CHECK:STDOUT: %foo1.call.loc8: init %empty_tuple.type = call %foo1.ref.loc8() // CHECK:STDOUT: %Cpp.ref.loc9: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: // CHECK:STDOUT: %Bar2.ref.loc9: type = name_ref Bar2, imports.%Bar2.decl [concrete = constants.%Bar2] -// CHECK:STDOUT: %foo1.ref.loc9: %foo1.type.0b8 = name_ref foo1, imports.%foo1.decl.191 [concrete = constants.%foo1.ba2] +// CHECK:STDOUT: %foo1.ref.loc9: %foo1.type = name_ref foo1, imports.%foo1.decl [concrete = constants.%foo1] // CHECK:STDOUT: %foo1.call.loc9: init %empty_tuple.type = call %foo1.ref.loc9() // CHECK:STDOUT: %Cpp.ref.loc10: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %Bar2.ref.loc10: type = name_ref Bar2, imports.%Bar2.decl [concrete = constants.%Bar2] diff --git a/toolchain/check/testdata/interop/cpp/class/struct.carbon b/toolchain/check/testdata/interop/cpp/class/struct.carbon index a8d7b78ad5d99..b92cb399d2dfb 100644 --- a/toolchain/check/testdata/interop/cpp/class/struct.carbon +++ b/toolchain/check/testdata/interop/cpp/class/struct.carbon @@ -567,11 +567,9 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: constants { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] // CHECK:STDOUT: %Bar1: type = class_type @Bar1 [concrete] -// CHECK:STDOUT: %foo1.type.148: type = fn_type @foo1.1 [concrete] -// CHECK:STDOUT: %foo1.8cd: %foo1.type.148 = struct_value () [concrete] +// CHECK:STDOUT: %foo1.type: type = fn_type @foo1 [concrete] +// CHECK:STDOUT: %foo1: %foo1.type = struct_value () [concrete] // CHECK:STDOUT: %Bar2: type = class_type @Bar2 [concrete] -// CHECK:STDOUT: %foo1.type.0b8: type = fn_type @foo1.2 [concrete] -// CHECK:STDOUT: %foo1.ba2: %foo1.type.0b8 = struct_value () [concrete] // CHECK:STDOUT: %foo2.type: type = fn_type @foo2 [concrete] // CHECK:STDOUT: %foo2: %foo2.type = struct_value () [concrete] // CHECK:STDOUT: } @@ -583,9 +581,8 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: %Bar1.decl: type = class_decl @Bar1 [concrete = constants.%Bar1] {} {} -// CHECK:STDOUT: %foo1.decl.c80: %foo1.type.148 = fn_decl @foo1.1 [concrete = constants.%foo1.8cd] {} {} +// CHECK:STDOUT: %foo1.decl: %foo1.type = fn_decl @foo1 [concrete = constants.%foo1] {} {} // CHECK:STDOUT: %Bar2.decl: type = class_decl @Bar2 [concrete = constants.%Bar2] {} {} -// CHECK:STDOUT: %foo1.decl.191: %foo1.type.0b8 = fn_decl @foo1.2 [concrete = constants.%foo1.ba2] {} {} // CHECK:STDOUT: %foo2.decl: %foo2.type = fn_decl @foo2 [concrete = constants.%foo2] {} {} // CHECK:STDOUT: } // CHECK:STDOUT: @@ -594,12 +591,12 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: // CHECK:STDOUT: %Bar1.ref: type = name_ref Bar1, imports.%Bar1.decl [concrete = constants.%Bar1] -// CHECK:STDOUT: %foo1.ref.loc8: %foo1.type.148 = name_ref foo1, imports.%foo1.decl.c80 [concrete = constants.%foo1.8cd] +// CHECK:STDOUT: %foo1.ref.loc8: %foo1.type = name_ref foo1, imports.%foo1.decl [concrete = constants.%foo1] // CHECK:STDOUT: %foo1.call.loc8: init %empty_tuple.type = call %foo1.ref.loc8() // CHECK:STDOUT: %Cpp.ref.loc9: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: // CHECK:STDOUT: %Bar2.ref.loc9: type = name_ref Bar2, imports.%Bar2.decl [concrete = constants.%Bar2] -// CHECK:STDOUT: %foo1.ref.loc9: %foo1.type.0b8 = name_ref foo1, imports.%foo1.decl.191 [concrete = constants.%foo1.ba2] +// CHECK:STDOUT: %foo1.ref.loc9: %foo1.type = name_ref foo1, imports.%foo1.decl [concrete = constants.%foo1] // CHECK:STDOUT: %foo1.call.loc9: init %empty_tuple.type = call %foo1.ref.loc9() // CHECK:STDOUT: %Cpp.ref.loc10: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %Bar2.ref.loc10: type = name_ref Bar2, imports.%Bar2.decl [concrete = constants.%Bar2] diff --git a/toolchain/check/testdata/interop/cpp/function/class.carbon b/toolchain/check/testdata/interop/cpp/function/class.carbon index 612642b51be51..c76b7e680f5d1 100644 --- a/toolchain/check/testdata/interop/cpp/function/class.carbon +++ b/toolchain/check/testdata/interop/cpp/function/class.carbon @@ -183,6 +183,8 @@ import Cpp library "definition_in_namespace_value_param_type.h"; fn F() { //@dump-sem-ir-begin Cpp.foo({}); + // Check that the parameter type was imported correctly. + var x: Cpp.N.C; //@dump-sem-ir-end } @@ -539,6 +541,7 @@ fn F() { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] // CHECK:STDOUT: %C: type = class_type @C [concrete] // CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %pattern_type.69f: type = pattern_type %C [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] // CHECK:STDOUT: %C.val: %C = struct_value () [concrete] @@ -550,8 +553,14 @@ fn F() { // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { // CHECK:STDOUT: .foo = %foo.decl +// CHECK:STDOUT: .N = %N // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } +// CHECK:STDOUT: %N: = namespace [concrete] { +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} // CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { // CHECK:STDOUT: // CHECK:STDOUT: } { @@ -561,7 +570,7 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // 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 @@ -570,11 +579,27 @@ fn F() { // 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: %Op.bound: = bound_method %.loc8_12.2, constants.%Op.dbb +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %x.patt: %pattern_type.69f = binding_pattern x [concrete] +// CHECK:STDOUT: %x.var_patt: %pattern_type.69f = var_pattern %x.patt [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %x.var: ref %C = var %x.var_patt +// CHECK:STDOUT: %.loc10: type = splice_block %C.ref [concrete = constants.%C] { +// CHECK:STDOUT: %Cpp.ref.loc10: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %N.ref: = name_ref N, imports.%N [concrete = imports.%N] +// CHECK:STDOUT: %C.ref: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: } +// CHECK:STDOUT: %x: ref %C = bind_name x, %x.var +// CHECK:STDOUT: %Op.bound.loc10: = bound_method %x.var, constants.%Op.dbb // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %.loc8_12.2, %Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.838 = addr_of %.loc8_12.2 -// CHECK:STDOUT: %no_op: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: %bound_method.loc10: = bound_method %x.var, %Op.specific_fn.1 +// CHECK:STDOUT: %addr.loc10: %ptr.838 = addr_of %x.var +// CHECK:STDOUT: %no_op.loc10: init %empty_tuple.type = call %bound_method.loc10(%addr.loc10) +// CHECK:STDOUT: %Op.bound.loc8: = bound_method %.loc8_12.2, constants.%Op.dbb +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8: = bound_method %.loc8_12.2, %Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc8: %ptr.838 = 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: diff --git a/toolchain/check/testdata/interop/cpp/function/struct.carbon b/toolchain/check/testdata/interop/cpp/function/struct.carbon index f82bf8d6e5cd3..9b0a9bde7a085 100644 --- a/toolchain/check/testdata/interop/cpp/function/struct.carbon +++ b/toolchain/check/testdata/interop/cpp/function/struct.carbon @@ -183,6 +183,8 @@ import Cpp library "definition_in_namespace_value_param_type.h"; fn F() { //@dump-sem-ir-begin Cpp.foo({}); + // Check that the parameter type was imported correctly. + var x: Cpp.N.S; //@dump-sem-ir-end } @@ -539,6 +541,7 @@ fn F() { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] // CHECK:STDOUT: %S: type = class_type @S [concrete] // CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %pattern_type.cd8: type = pattern_type %S [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] // CHECK:STDOUT: %S.val: %S = struct_value () [concrete] @@ -550,8 +553,14 @@ fn F() { // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { // CHECK:STDOUT: .foo = %foo.decl +// CHECK:STDOUT: .N = %N // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } +// CHECK:STDOUT: %N: = namespace [concrete] { +// CHECK:STDOUT: .S = %S.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %S.decl: type = class_decl @S [concrete = constants.%S] {} {} // CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { // CHECK:STDOUT: // CHECK:STDOUT: } { @@ -561,7 +570,7 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // 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 @@ -570,11 +579,27 @@ fn F() { // 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: %Op.bound: = bound_method %.loc8_12.2, constants.%Op.9b3 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %x.patt: %pattern_type.cd8 = binding_pattern x [concrete] +// CHECK:STDOUT: %x.var_patt: %pattern_type.cd8 = var_pattern %x.patt [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %x.var: ref %S = var %x.var_patt +// CHECK:STDOUT: %.loc10: type = splice_block %S.ref [concrete = constants.%S] { +// CHECK:STDOUT: %Cpp.ref.loc10: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %N.ref: = name_ref N, imports.%N [concrete = imports.%N] +// CHECK:STDOUT: %S.ref: type = name_ref S, imports.%S.decl [concrete = constants.%S] +// CHECK:STDOUT: } +// CHECK:STDOUT: %x: ref %S = bind_name x, %x.var +// CHECK:STDOUT: %Op.bound.loc10: = bound_method %x.var, constants.%Op.9b3 // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %.loc8_12.2, %Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.edf = addr_of %.loc8_12.2 -// CHECK:STDOUT: %no_op: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: %bound_method.loc10: = bound_method %x.var, %Op.specific_fn.1 +// CHECK:STDOUT: %addr.loc10: %ptr.edf = addr_of %x.var +// CHECK:STDOUT: %no_op.loc10: init %empty_tuple.type = call %bound_method.loc10(%addr.loc10) +// CHECK:STDOUT: %Op.bound.loc8: = bound_method %.loc8_12.2, constants.%Op.9b3 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8: = bound_method %.loc8_12.2, %Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc8: %ptr.edf = 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: diff --git a/toolchain/check/testdata/interop/cpp/function/union.carbon b/toolchain/check/testdata/interop/cpp/function/union.carbon index b4127ed6f772d..8eca37d7049d3 100644 --- a/toolchain/check/testdata/interop/cpp/function/union.carbon +++ b/toolchain/check/testdata/interop/cpp/function/union.carbon @@ -199,6 +199,8 @@ import Cpp library "definition_in_namespace_value_param_type.h"; fn F() { //@dump-sem-ir-begin Cpp.foo({}); + // Check that the parameter type was imported correctly. + var x: Cpp.N.U; //@dump-sem-ir-end } @@ -555,6 +557,7 @@ fn F() { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] // CHECK:STDOUT: %U: type = class_type @U [concrete] // CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %pattern_type.eb9: type = pattern_type %U [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] // CHECK:STDOUT: %U.val: %U = struct_value () [concrete] @@ -566,8 +569,14 @@ fn F() { // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { // CHECK:STDOUT: .foo = %foo.decl +// CHECK:STDOUT: .N = %N // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } +// CHECK:STDOUT: %N: = namespace [concrete] { +// CHECK:STDOUT: .U = %U.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %U.decl: type = class_decl @U [concrete = constants.%U] {} {} // CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { // CHECK:STDOUT: // CHECK:STDOUT: } { @@ -577,7 +586,7 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // 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 @@ -586,11 +595,27 @@ fn F() { // 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: %Op.bound: = bound_method %.loc8_12.2, constants.%Op.d5d +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %x.patt: %pattern_type.eb9 = binding_pattern x [concrete] +// CHECK:STDOUT: %x.var_patt: %pattern_type.eb9 = var_pattern %x.patt [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %x.var: ref %U = var %x.var_patt +// CHECK:STDOUT: %.loc10: type = splice_block %U.ref [concrete = constants.%U] { +// CHECK:STDOUT: %Cpp.ref.loc10: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %N.ref: = name_ref N, imports.%N [concrete = imports.%N] +// CHECK:STDOUT: %U.ref: type = name_ref U, imports.%U.decl [concrete = constants.%U] +// CHECK:STDOUT: } +// CHECK:STDOUT: %x: ref %U = bind_name x, %x.var +// CHECK:STDOUT: %Op.bound.loc10: = bound_method %x.var, constants.%Op.d5d // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %.loc8_12.2, %Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.87e = addr_of %.loc8_12.2 -// CHECK:STDOUT: %no_op: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: %bound_method.loc10: = bound_method %x.var, %Op.specific_fn.1 +// CHECK:STDOUT: %addr.loc10: %ptr.87e = addr_of %x.var +// CHECK:STDOUT: %no_op.loc10: init %empty_tuple.type = call %bound_method.loc10(%addr.loc10) +// CHECK:STDOUT: %Op.bound.loc8: = bound_method %.loc8_12.2, constants.%Op.d5d +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8: = bound_method %.loc8_12.2, %Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc8: %ptr.87e = 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: