From ff9154b978f8539db4e72a45d316c303ad2aa54f Mon Sep 17 00:00:00 2001 From: Boaz Brickner Date: Mon, 7 Jul 2025 17:02:47 +0200 Subject: [PATCH] Push a decl name scope before calling `CalleePatternMatch()` (#5771) Otherwise the return values of different functions collide. Part of #5063. --- toolchain/check/import_cpp.cpp | 4 + .../interop/cpp/function/return.carbon | 80 +++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/toolchain/check/import_cpp.cpp b/toolchain/check/import_cpp.cpp index 8c8469cefb87..b07322e7f701 100644 --- a/toolchain/check/import_cpp.cpp +++ b/toolchain/check/import_cpp.cpp @@ -697,10 +697,12 @@ static auto CreateFunctionParamsInsts(Context& context, SemIR::LocId loc_id, if (SemIR::ErrorInst::InstId == return_slot_pattern_id) { return std::nullopt; } + // TODO: Add support for implicit parameters. auto call_params_id = CalleePatternMatch( context, /*implicit_param_patterns_id=*/SemIR::InstBlockId::None, param_patterns_id, return_slot_pattern_id); + return {{.param_patterns_id = param_patterns_id, .return_slot_pattern_id = return_slot_pattern_id, .call_params_id = call_params_id}}; @@ -726,6 +728,7 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id, return SemIR::ErrorInst::InstId; } + context.scope_stack().PushForDeclName(); context.inst_block_stack().Push(); context.pattern_block_stack().Push(); @@ -734,6 +737,7 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id, auto pattern_block_id = context.pattern_block_stack().Pop(); auto decl_block_id = context.inst_block_stack().Pop(); + context.scope_stack().Pop(); if (!function_params_insts.has_value()) { return SemIR::ErrorInst::InstId; diff --git a/toolchain/check/testdata/interop/cpp/function/return.carbon b/toolchain/check/testdata/interop/cpp/function/return.carbon index a998ed0e6116..dbcd9ba1141d 100644 --- a/toolchain/check/testdata/interop/cpp/function/return.carbon +++ b/toolchain/check/testdata/interop/cpp/function/return.carbon @@ -52,6 +52,31 @@ fn F() { //@dump-sem-ir-end } +// ============================================================================ +// Multiple function with a return value +// ============================================================================ + +// --- multiple.h + +auto foo1() -> short; +auto foo2() -> int; + +// --- import_multiple.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "multiple.h"; + +fn IngestI16(x: i16); +fn IngestI32(x: i32); + +fn F() { + //@dump-sem-ir-begin + IngestI16(Cpp.foo1()); + IngestI32(Cpp.foo2()); + //@dump-sem-ir-end +} + // ============================================================================ // float // ============================================================================ @@ -155,6 +180,61 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: --- import_multiple.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %int_16: Core.IntLiteral = int_value 16 [concrete] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %i16: type = class_type @Int, @Int(%int_16) [concrete] +// CHECK:STDOUT: %IngestI16.type: type = fn_type @IngestI16 [concrete] +// CHECK:STDOUT: %IngestI16: %IngestI16.type = struct_value () [concrete] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %IngestI32.type: type = fn_type @IngestI32 [concrete] +// CHECK:STDOUT: %IngestI32: %IngestI32.type = struct_value () [concrete] +// CHECK:STDOUT: %foo1.type: type = fn_type @foo1 [concrete] +// CHECK:STDOUT: %foo1: %foo1.type = struct_value () [concrete] +// CHECK:STDOUT: %foo2.type: type = fn_type @foo2 [concrete] +// CHECK:STDOUT: %foo2: %foo2.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .foo1 = %foo1.decl +// CHECK:STDOUT: .foo2 = %foo2.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %foo1.decl: %foo1.type = fn_decl @foo1 [concrete = constants.%foo1] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: %foo2.decl: %foo2.type = fn_decl @foo2 [concrete = constants.%foo2] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %IngestI16.ref: %IngestI16.type = name_ref IngestI16, file.%IngestI16.decl [concrete = constants.%IngestI16] +// CHECK:STDOUT: %Cpp.ref.loc11: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo1.ref: %foo1.type = name_ref foo1, imports.%foo1.decl [concrete = constants.%foo1] +// CHECK:STDOUT: %foo1.call: init %i16 = call %foo1.ref() +// CHECK:STDOUT: %.loc11_22.1: %i16 = value_of_initializer %foo1.call +// CHECK:STDOUT: %.loc11_22.2: %i16 = converted %foo1.call, %.loc11_22.1 +// CHECK:STDOUT: %IngestI16.call: init %empty_tuple.type = call %IngestI16.ref(%.loc11_22.2) +// CHECK:STDOUT: %IngestI32.ref: %IngestI32.type = name_ref IngestI32, file.%IngestI32.decl [concrete = constants.%IngestI32] +// CHECK:STDOUT: %Cpp.ref.loc12: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo2.ref: %foo2.type = name_ref foo2, imports.%foo2.decl [concrete = constants.%foo2] +// CHECK:STDOUT: %foo2.call: init %i32 = call %foo2.ref() +// CHECK:STDOUT: %.loc12_22.1: %i32 = value_of_initializer %foo2.call +// CHECK:STDOUT: %.loc12_22.2: %i32 = converted %foo2.call, %.loc12_22.1 +// CHECK:STDOUT: %IngestI32.call: init %empty_tuple.type = call %IngestI32.ref(%.loc12_22.2) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: --- fail_todo_import_float.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants {