Implement initialization for C++ thunk parameters. (#5938)

When initializing a C++ thunk parameter:

* If we have an initializing expression, materialize a temporary and
pass its address.
* If we have a reference expression, pass its address directly.
* If we have a value expression with a pointer value representation,
pass the pointer.
* Otherwise, create a new temporary and initialize it with a copy of the
argument, and pass its address.
This commit is contained in:
Richard Smith
2025-08-08 23:38:47 +00:00
committed by GitHub
parent 2e22733372
commit e0de9ddf05
10 changed files with 665 additions and 446 deletions
+40 -94
View File
@@ -573,20 +573,14 @@ fn F() {
// CHECK:STDOUT: %.loc8_12.4: ref %S = temporary %.loc8_12.2, %.loc8_12.3
// CHECK:STDOUT: %.loc8_14.1: ref %S = converted %.loc8_12.1, %.loc8_12.4
// CHECK:STDOUT: %.loc8_14.2: %S = bind_value %.loc8_14.1
// CHECK:STDOUT: %.loc8_22.1: ref %S = temporary_storage
// CHECK:STDOUT: %.loc8_22.2: init %S = initialize_from %.loc8_14.2 to %.loc8_22.1
// CHECK:STDOUT: %addr.loc8_22.1: %ptr.5c7 = addr_of %.loc8_22.1
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_22.1)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_22: <bound method> = bound_method %.loc8_22.1, constants.%T.as.Destroy.impl.Op.ab5
// CHECK:STDOUT: %.loc8_14.3: ref %S = value_as_ref %.loc8_14.2
// CHECK:STDOUT: %addr.loc8_22: %ptr.5c7 = addr_of %.loc8_14.3
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_22)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.ab5
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method.loc8_22: <bound method> = bound_method %.loc8_22.1, %T.as.Destroy.impl.Op.specific_fn.1
// CHECK:STDOUT: %addr.loc8_22.2: %ptr.5c7 = addr_of %.loc8_22.1
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_22: init %empty_tuple.type = call %bound_method.loc8_22(%addr.loc8_22.2)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_12: <bound method> = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.ab5
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method.loc8_12: <bound method> = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.2
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn
// CHECK:STDOUT: %addr.loc8_12: %ptr.5c7 = addr_of %.loc8_12.2
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_12: init %empty_tuple.type = call %bound_method.loc8_12(%addr.loc8_12)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc8_12)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -650,8 +644,6 @@ fn F() {
// CHECK:STDOUT: %foo__carbon_thunk.type: type = fn_type @foo__carbon_thunk [concrete]
// CHECK:STDOUT: %foo__carbon_thunk: %foo__carbon_thunk.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.642: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%S) [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.ab5: %T.as.Destroy.impl.Op.type.642 = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -681,15 +673,8 @@ fn F() {
// CHECK:STDOUT: %Cpp.ref.loc15_17: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %S.ref: type = name_ref S, imports.%S.decl [concrete = constants.%S]
// CHECK:STDOUT: %.loc15_14: %S = converted %.loc15_12, <error> [concrete = <error>]
// CHECK:STDOUT: %.loc15_22.1: ref %S = temporary_storage
// CHECK:STDOUT: %.loc15_22.2: init %S = initialize_from <error> to %.loc15_22.1 [concrete = <error>]
// CHECK:STDOUT: %addr.loc15_22.1: %ptr.5c7 = addr_of %.loc15_22.1
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc15_22.1)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc15_22.1, constants.%T.as.Destroy.impl.Op.ab5
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc15_22.1, %T.as.Destroy.impl.Op.specific_fn
// CHECK:STDOUT: %addr.loc15_22.2: %ptr.5c7 = addr_of %.loc15_22.1
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc15_22.2)
// CHECK:STDOUT: %addr: %ptr.5c7 = addr_of <error> [concrete = <error>]
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -704,8 +689,6 @@ fn F() {
// CHECK:STDOUT: %foo__carbon_thunk.type: type = fn_type @foo__carbon_thunk [concrete]
// CHECK:STDOUT: %foo__carbon_thunk: %foo__carbon_thunk.type = struct_value () [concrete]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.642: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%S) [concrete]
// CHECK:STDOUT: %T.as.Destroy.impl.Op.ab5: %T.as.Destroy.impl.Op.type.642 = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -735,15 +718,8 @@ fn F() {
// CHECK:STDOUT: %Cpp.ref.loc15_17: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %S.ref: type = name_ref S, imports.%S.decl [concrete = constants.%S]
// CHECK:STDOUT: %.loc15_14: %S = converted %.loc15_12, <error> [concrete = <error>]
// CHECK:STDOUT: %.loc15_22.1: ref %S = temporary_storage
// CHECK:STDOUT: %.loc15_22.2: init %S = initialize_from <error> to %.loc15_22.1 [concrete = <error>]
// CHECK:STDOUT: %addr.loc15_22.1: %ptr.5c7 = addr_of %.loc15_22.1
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc15_22.1)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc15_22.1, constants.%T.as.Destroy.impl.Op.ab5
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc15_22.1, %T.as.Destroy.impl.Op.specific_fn
// CHECK:STDOUT: %addr.loc15_22.2: %ptr.5c7 = addr_of %.loc15_22.1
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc15_22.2)
// CHECK:STDOUT: %addr: %ptr.5c7 = addr_of <error> [concrete = <error>]
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -800,10 +776,9 @@ fn F() {
// CHECK:STDOUT: %.loc8_12.4: ref %S = temporary %.loc8_12.2, %.loc8_12.3
// CHECK:STDOUT: %.loc8_14.1: ref %S = converted %.loc8_12.1, %.loc8_12.4
// CHECK:STDOUT: %.loc8_14.2: %S = bind_value %.loc8_14.1
// CHECK:STDOUT: %.loc8_24.1: ref %S = temporary_storage
// CHECK:STDOUT: %.loc8_24.2: init %S = initialize_from %.loc8_14.2 to %.loc8_24.1
// CHECK:STDOUT: %addr.loc8_24.1: %ptr.edf = addr_of %.loc8_24.1
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_24.1)
// CHECK:STDOUT: %.loc8_14.3: ref %S = value_as_ref %.loc8_14.2
// CHECK:STDOUT: %addr.loc8_24: %ptr.edf = addr_of %.loc8_14.3
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_24)
// 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]
@@ -820,16 +795,11 @@ fn F() {
// CHECK:STDOUT: %bound_method.loc10: <bound method> = bound_method %x.var, %T.as.Destroy.impl.Op.specific_fn.1
// CHECK:STDOUT: %addr.loc10: %ptr.edf = addr_of %x.var
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc10: init %empty_tuple.type = call %bound_method.loc10(%addr.loc10)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_24: <bound method> = bound_method %.loc8_24.1, constants.%T.as.Destroy.impl.Op.9b3
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8: <bound method> = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.9b3
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method.loc8_24: <bound method> = bound_method %.loc8_24.1, %T.as.Destroy.impl.Op.specific_fn.2
// CHECK:STDOUT: %addr.loc8_24.2: %ptr.edf = addr_of %.loc8_24.1
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_24: init %empty_tuple.type = call %bound_method.loc8_24(%addr.loc8_24.2)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_12: <bound method> = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.9b3
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method.loc8_12: <bound method> = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.3
// CHECK:STDOUT: %bound_method.loc8: <bound method> = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.2
// CHECK:STDOUT: %addr.loc8_12: %ptr.edf = addr_of %.loc8_12.2
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_12: init %empty_tuple.type = call %bound_method.loc8_12(%addr.loc8_12)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8: init %empty_tuple.type = call %bound_method.loc8(%addr.loc8_12)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -891,20 +861,14 @@ fn F() {
// CHECK:STDOUT: %.loc8_15.4: ref %S = temporary %.loc8_15.2, %.loc8_15.3
// CHECK:STDOUT: %.loc8_17.1: ref %S = converted %.loc8_15.1, %.loc8_15.4
// CHECK:STDOUT: %.loc8_17.2: %S = bind_value %.loc8_17.1
// CHECK:STDOUT: %.loc8_31.1: ref %S = temporary_storage
// CHECK:STDOUT: %.loc8_31.2: init %S = initialize_from %.loc8_17.2 to %.loc8_31.1
// CHECK:STDOUT: %addr.loc8_31.1: %ptr.887 = addr_of %.loc8_31.1
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_31.1)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_31: <bound method> = bound_method %.loc8_31.1, constants.%T.as.Destroy.impl.Op.463
// CHECK:STDOUT: %.loc8_17.3: ref %S = value_as_ref %.loc8_17.2
// CHECK:STDOUT: %addr.loc8_31: %ptr.887 = addr_of %.loc8_17.3
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_31)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc8_15.2, constants.%T.as.Destroy.impl.Op.463
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method.loc8_31: <bound method> = bound_method %.loc8_31.1, %T.as.Destroy.impl.Op.specific_fn.1
// CHECK:STDOUT: %addr.loc8_31.2: %ptr.887 = addr_of %.loc8_31.1
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_31: init %empty_tuple.type = call %bound_method.loc8_31(%addr.loc8_31.2)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_15: <bound method> = bound_method %.loc8_15.2, constants.%T.as.Destroy.impl.Op.463
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method.loc8_15: <bound method> = bound_method %.loc8_15.2, %T.as.Destroy.impl.Op.specific_fn.2
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc8_15.2, %T.as.Destroy.impl.Op.specific_fn
// CHECK:STDOUT: %addr.loc8_15: %ptr.887 = addr_of %.loc8_15.2
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_15: init %empty_tuple.type = call %bound_method.loc8_15(%addr.loc8_15)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc8_15)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -962,10 +926,9 @@ fn F() {
// CHECK:STDOUT: %.loc8_12.4: ref %S = temporary %.loc8_12.2, %.loc8_12.3
// CHECK:STDOUT: %.loc8_14.1: ref %S = converted %.loc8_12.1, %.loc8_12.4
// CHECK:STDOUT: %.loc8_14.2: %S = bind_value %.loc8_14.1
// CHECK:STDOUT: %.loc8_24.1: ref %S = temporary_storage
// CHECK:STDOUT: %.loc8_24.2: init %S = initialize_from %.loc8_14.2 to %.loc8_24.1
// CHECK:STDOUT: %addr.loc8_24.1: %ptr.149 = addr_of %.loc8_24.1
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_24.1)
// CHECK:STDOUT: %.loc8_14.3: ref %S = value_as_ref %.loc8_14.2
// CHECK:STDOUT: %addr.loc8_24: %ptr.149 = addr_of %.loc8_14.3
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_24)
// 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]
@@ -981,16 +944,11 @@ fn F() {
// CHECK:STDOUT: %bound_method.loc9: <bound method> = bound_method %x.var, %T.as.Destroy.impl.Op.specific_fn.1
// CHECK:STDOUT: %addr.loc9: %ptr.820 = addr_of %x.var
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc9: init %empty_tuple.type = call %bound_method.loc9(%addr.loc9)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_24: <bound method> = bound_method %.loc8_24.1, constants.%T.as.Destroy.impl.Op.952
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8: <bound method> = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.952
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method.loc8_24: <bound method> = bound_method %.loc8_24.1, %T.as.Destroy.impl.Op.specific_fn.2
// CHECK:STDOUT: %addr.loc8_24.2: %ptr.149 = addr_of %.loc8_24.1
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_24: init %empty_tuple.type = call %bound_method.loc8_24(%addr.loc8_24.2)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_12: <bound method> = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.952
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method.loc8_12: <bound method> = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.3
// CHECK:STDOUT: %bound_method.loc8: <bound method> = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.2
// CHECK:STDOUT: %addr.loc8_12: %ptr.149 = addr_of %.loc8_12.2
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_12: init %empty_tuple.type = call %bound_method.loc8_12(%addr.loc8_12)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8: init %empty_tuple.type = call %bound_method.loc8(%addr.loc8_12)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -1048,20 +1006,14 @@ fn F() {
// CHECK:STDOUT: %.loc9_12.4: ref %S = temporary %.loc9_12.2, %.loc9_12.3
// CHECK:STDOUT: %.loc9_14.1: ref %S = converted %.loc9_12.1, %.loc9_12.4
// CHECK:STDOUT: %.loc9_14.2: %S = bind_value %.loc9_14.1
// CHECK:STDOUT: %.loc9_22.1: ref %S = temporary_storage
// CHECK:STDOUT: %.loc9_22.2: init %S = initialize_from %.loc9_14.2 to %.loc9_22.1
// CHECK:STDOUT: %addr.loc9_22.1: %ptr.5c7 = addr_of %.loc9_22.1
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc9_22.1)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc9_22: <bound method> = bound_method %.loc9_22.1, constants.%T.as.Destroy.impl.Op.ab5
// CHECK:STDOUT: %.loc9_14.3: ref %S = value_as_ref %.loc9_14.2
// CHECK:STDOUT: %addr.loc9_22: %ptr.5c7 = addr_of %.loc9_14.3
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc9_22)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc9_12.2, constants.%T.as.Destroy.impl.Op.ab5
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method.loc9_22: <bound method> = bound_method %.loc9_22.1, %T.as.Destroy.impl.Op.specific_fn.1
// CHECK:STDOUT: %addr.loc9_22.2: %ptr.5c7 = addr_of %.loc9_22.1
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc9_22: init %empty_tuple.type = call %bound_method.loc9_22(%addr.loc9_22.2)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc9_12: <bound method> = bound_method %.loc9_12.2, constants.%T.as.Destroy.impl.Op.ab5
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method.loc9_12: <bound method> = bound_method %.loc9_12.2, %T.as.Destroy.impl.Op.specific_fn.2
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc9_12.2, %T.as.Destroy.impl.Op.specific_fn
// CHECK:STDOUT: %addr.loc9_12: %ptr.5c7 = addr_of %.loc9_12.2
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc9_12: init %empty_tuple.type = call %bound_method.loc9_12(%addr.loc9_12)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc9_12)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -1115,24 +1067,18 @@ fn F() {
// CHECK:STDOUT: %.loc8_12.4: ref %S = temporary %.loc8_12.2, %.loc8_12.3
// CHECK:STDOUT: %.loc8_14.1: ref %S = converted %.loc8_12.1, %.loc8_12.4
// CHECK:STDOUT: %.loc8_14.2: %S = bind_value %.loc8_14.1
// CHECK:STDOUT: %.loc8_22.1: ref %S = temporary_storage
// CHECK:STDOUT: %.loc8_22.2: init %S = initialize_from %.loc8_14.2 to %.loc8_22.1
// CHECK:STDOUT: %addr.loc8_22.1: %ptr.5c7 = addr_of %.loc8_22.1
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_22.1)
// CHECK:STDOUT: %.loc8_14.3: ref %S = value_as_ref %.loc8_14.2
// CHECK:STDOUT: %addr.loc8_22: %ptr.5c7 = addr_of %.loc8_14.3
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_22)
// CHECK:STDOUT: %Cpp.ref.loc9: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %S.ref.loc9: type = name_ref S, imports.%S.decl [concrete = constants.%S]
// CHECK:STDOUT: %bar.ref: %S.bar.type = name_ref bar, imports.%S.bar.decl [concrete = constants.%S.bar]
// CHECK:STDOUT: %S.bar.call: init %empty_tuple.type = call %bar.ref()
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_22: <bound method> = bound_method %.loc8_22.1, constants.%T.as.Destroy.impl.Op.ab5
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.ab5
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method.loc8_22: <bound method> = bound_method %.loc8_22.1, %T.as.Destroy.impl.Op.specific_fn.1
// CHECK:STDOUT: %addr.loc8_22.2: %ptr.5c7 = addr_of %.loc8_22.1
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_22: init %empty_tuple.type = call %bound_method.loc8_22(%addr.loc8_22.2)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_12: <bound method> = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.ab5
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %bound_method.loc8_12: <bound method> = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.2
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn
// CHECK:STDOUT: %addr.loc8_12: %ptr.5c7 = addr_of %.loc8_12.2
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_12: init %empty_tuple.type = call %bound_method.loc8_12(%addr.loc8_12)
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc8_12)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT: