Fix passing mode computation for methods. (#7225)

We were incorrectly computing the index of the Clang implicit conversion
corresponding to method arguments. This led to wrong code and a crash in
lowering due to a calling convention mismatch.

Fixes #7224.

Assisted-by: Gemini via Antigravity
This commit is contained in:
Richard Smith
2026-05-18 20:30:23 +00:00
committed by GitHub
parent 773ecdfac6
commit b87f848db4
3 changed files with 75 additions and 33 deletions
@@ -1189,7 +1189,6 @@ fn F() {
// CHECK:STDOUT: %int_3.1ba: Core.IntLiteral = int_value 3 [concrete]
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
// CHECK:STDOUT: %i32.builtin: type = int_type signed, %int_32 [concrete]
// CHECK:STDOUT: %pattern_type.7ce: type = pattern_type %i32 [concrete]
// CHECK:STDOUT: %operator_LessLess__carbon_thunk.type: type = fn_type @operator_LessLess__carbon_thunk [concrete]
// CHECK:STDOUT: %operator_LessLess__carbon_thunk: %operator_LessLess__carbon_thunk.type = struct_value () [concrete]
@@ -1253,12 +1252,8 @@ fn F() {
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.577: <bound method> = bound_method %int_42.20e, %Core.IntLiteral.as.ImplicitAs.impl.Convert.f1a [concrete]
// CHECK:STDOUT: %bound_method.cd5: <bound method> = bound_method %int_42.20e, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete]
// CHECK:STDOUT: %int_42.c68: %i32 = int_value 42 [concrete]
// CHECK:STDOUT: %.1a9: ref %i32 = temporary invalid, %int_42.c68 [concrete]
// CHECK:STDOUT: %Destroy.Op.type.bae255.2: type = fn_type @Destroy.Op.loc48_30.2 [concrete]
// CHECK:STDOUT: %Destroy.Op.651ba6.2: %Destroy.Op.type.bae255.2 = struct_value () [concrete]
// CHECK:STDOUT: %Destroy.Op.bound: <bound method> = bound_method %.1a9, %Destroy.Op.651ba6.2 [concrete]
// CHECK:STDOUT: %Destroy.Op.type.bae255.3: type = fn_type @Destroy.Op.loc45 [concrete]
// CHECK:STDOUT: %Destroy.Op.651ba6.3: %Destroy.Op.type.bae255.3 = struct_value () [concrete]
// CHECK:STDOUT: %Destroy.Op.type: type = fn_type @Destroy.Op [concrete]
// CHECK:STDOUT: %Destroy.Op: %Destroy.Op.type = struct_value () [concrete]
// CHECK:STDOUT: %C.cpp_destructor.type: type = fn_type @C.cpp_destructor [concrete]
// CHECK:STDOUT: %C.cpp_destructor: %C.cpp_destructor.type = struct_value () [concrete]
// CHECK:STDOUT: %C.Op.type: type = fn_type @C.Op [concrete]
@@ -1880,26 +1875,24 @@ fn F() {
// CHECK:STDOUT: %specific_fn.loc48: <specific function> = specific_function %impl.elem0.loc48, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
// CHECK:STDOUT: %bound_method.loc48_30.2: <bound method> = bound_method %int_42, %specific_fn.loc48 [concrete = constants.%bound_method.cd5]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc48: init %i32 = call %bound_method.loc48_30.2(%int_42) [concrete = constants.%int_42.c68]
// CHECK:STDOUT: %.loc48_30.1: init %i32 = converted %int_42, %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc48 [concrete = constants.%int_42.c68]
// CHECK:STDOUT: %.loc48_30.2: ref %i32 = temporary_storage
// CHECK:STDOUT: %.loc48_30.3: ref %i32 = temporary %.loc48_30.2, %.loc48_30.1 [concrete = constants.%.1a9]
// CHECK:STDOUT: %C.cpp_operator.call: init %i32 = call %C.cpp_operator.bound(%c1.ref.loc48, %.loc48_30.3)
// CHECK:STDOUT: %.loc48_30.1: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc48 [concrete = constants.%int_42.c68]
// CHECK:STDOUT: %.loc48_30.2: %i32 = converted %int_42, %.loc48_30.1 [concrete = constants.%int_42.c68]
// CHECK:STDOUT: %C.cpp_operator.call: init %i32 = call %C.cpp_operator.bound(%c1.ref.loc48, %.loc48_30.2)
// CHECK:STDOUT: %i32: type = type_literal constants.%i32 [concrete = constants.%i32]
// CHECK:STDOUT: %.loc48_32.1: %i32 = value_of_initializer %C.cpp_operator.call
// CHECK:STDOUT: %.loc48_32.2: %i32 = converted %C.cpp_operator.call, %.loc48_32.1
// CHECK:STDOUT: %index: %i32 = value_binding index, %.loc48_32.2
// CHECK:STDOUT: %Destroy.Op.call.loc48: init %empty_tuple.type = call constants.%Destroy.Op.bound(constants.%.1a9)
// CHECK:STDOUT: %Destroy.Op.bound.loc45: <bound method> = bound_method %.loc45_44.3, constants.%Destroy.Op.651ba6.3
// CHECK:STDOUT: %Destroy.Op.bound.loc45: <bound method> = bound_method %.loc45_44.3, constants.%Destroy.Op
// CHECK:STDOUT: %Destroy.Op.call.loc45: init %empty_tuple.type = call %Destroy.Op.bound.loc45(%.loc45_44.3)
// CHECK:STDOUT: %Destroy.Op.bound.loc44: <bound method> = bound_method %.loc44_47.3, constants.%Destroy.Op.651ba6.3
// CHECK:STDOUT: %Destroy.Op.bound.loc44: <bound method> = bound_method %.loc44_47.3, constants.%Destroy.Op
// CHECK:STDOUT: %Destroy.Op.call.loc44: init %empty_tuple.type = call %Destroy.Op.bound.loc44(%.loc44_47.3)
// CHECK:STDOUT: %Destroy.Op.bound.loc43: <bound method> = bound_method %.loc43_35.3, constants.%Destroy.Op.651ba6.3
// CHECK:STDOUT: %Destroy.Op.bound.loc43: <bound method> = bound_method %.loc43_35.3, constants.%Destroy.Op
// CHECK:STDOUT: %Destroy.Op.call.loc43: init %empty_tuple.type = call %Destroy.Op.bound.loc43(%.loc43_35.3)
// CHECK:STDOUT: %Destroy.Op.bound.loc42: <bound method> = bound_method %.loc42_38.3, constants.%Destroy.Op.651ba6.3
// CHECK:STDOUT: %Destroy.Op.bound.loc42: <bound method> = bound_method %.loc42_38.3, constants.%Destroy.Op
// CHECK:STDOUT: %Destroy.Op.call.loc42: init %empty_tuple.type = call %Destroy.Op.bound.loc42(%.loc42_38.3)
// CHECK:STDOUT: %Destroy.Op.bound.loc41: <bound method> = bound_method %.loc41_35.3, constants.%Destroy.Op.651ba6.3
// CHECK:STDOUT: %Destroy.Op.bound.loc41: <bound method> = bound_method %.loc41_35.3, constants.%Destroy.Op
// CHECK:STDOUT: %Destroy.Op.call.loc41: init %empty_tuple.type = call %Destroy.Op.bound.loc41(%.loc41_35.3)
// CHECK:STDOUT: %Destroy.Op.bound.loc40: <bound method> = bound_method %.loc40_31.3, constants.%Destroy.Op.651ba6.3
// CHECK:STDOUT: %Destroy.Op.bound.loc40: <bound method> = bound_method %.loc40_31.3, constants.%Destroy.Op
// CHECK:STDOUT: %Destroy.Op.call.loc40: init %empty_tuple.type = call %Destroy.Op.bound.loc40(%.loc40_31.3)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %C.Op.bound.loc23: <bound method> = bound_method %.loc23_38.3, constants.%C.Op
@@ -1953,14 +1946,7 @@ fn F() {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Destroy.Op.loc48_30.1(%self.param: ref %i32.builtin) = "no_op";
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Destroy.Op.loc48_30.2(%self.param: ref %i32) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Destroy.Op.loc45(%self.param: ref bool) = "no_op";
// CHECK:STDOUT: fn @Destroy.Op(%self.param: ref bool) = "no_op";
// CHECK:STDOUT:
// CHECK:STDOUT: --- multiple_calls.carbon
// CHECK:STDOUT:
@@ -3189,7 +3175,9 @@ fn F() {
// CHECK:STDOUT: %c2.ref: ref %C = name_ref c2, %c2
// CHECK:STDOUT: %C.cpp_operator.bound.loc10: <bound method> = bound_method %c1.ref.loc10, imports.%C.cpp_operator.decl.828f43.2
// CHECK:STDOUT: %.loc10_3: ref %C = splice_block %c3.var {}
// CHECK:STDOUT: %addr.loc10_29.1: %ptr.d9e = addr_of %c2.ref
// CHECK:STDOUT: %.loc10_31.1: %C = acquire_value %c2.ref
// CHECK:STDOUT: %.loc10_31.2: ref %C = value_as_ref %.loc10_31.1
// CHECK:STDOUT: %addr.loc10_29.1: %ptr.d9e = addr_of %.loc10_31.2
// CHECK:STDOUT: %addr.loc10_29.2: %ptr.d9e = addr_of %.loc10_3
// CHECK:STDOUT: %operator_Plus__carbon_thunk.call: init %empty_tuple.type = call imports.%operator_Plus__carbon_thunk.decl(%c1.ref.loc10, %addr.loc10_29.1, %addr.loc10_29.2)
// CHECK:STDOUT: %.loc10_29: init %C to %.loc10_3 = mark_in_place_init %operator_Plus__carbon_thunk.call