Skip to content

Commit d37f1ae

Browse files
authored
Add return value support to C++ thunks. (#5976)
Based on #5948. A couple of tricky parts: * When generating the C++ side of the thunk, we are given a pointer to the location to emplace the return value. The only mechanism C++ provides to perform this emplacement is using placement `operator new`, which requires a library function in the `<new>` header. We handle this by declaring that library function ourselves, and rely on Clang not actually needing a definition for it (which the standard library owns). * On the Carbon side of the thunk, we want to form an initializing expression as the result of the call. We don't have a way of expressing in SemIR that an initializing expression performs its initialization by storing through a pointer, so this PR adds a new initializing instruction, `InPlaceInit`, to model an initialization that's performed opaquely in-place.
1 parent 1331ade commit d37f1ae

17 files changed

+1039
-96
lines changed

toolchain/check/cpp_thunk.cpp

Lines changed: 184 additions & 47 deletions
Large diffs are not rendered by default.

toolchain/check/import_cpp.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,34 @@ static auto GenerateCppIncludesHeaderCode(
102102
<< "\"\n";
103103
}
104104
}
105+
106+
// Inject a declaration of placement operator new, because the code we
107+
// generate in thunks depends on it for placement new expressions. Clang has
108+
// special-case logic for lowering a new-expression using this, so a
109+
// definition is not required.
110+
// TODO: This is a hack. We should be able to directly generate Clang AST to
111+
// construct objects in-place without this.
112+
// TODO: Once we can rely on libc++ being available, consider including
113+
// `<__new/placement_new_delete.h>` instead.
114+
code_stream << R"(# 1 "<carbon-internal>"
115+
#undef constexpr
116+
#if __cplusplus > 202302L
117+
constexpr
118+
#endif
119+
#undef void
120+
#undef operator
121+
#undef new
122+
void* operator new(__SIZE_TYPE__, void*)
123+
#if __cplusplus < 201103L
124+
#undef throw
125+
throw()
126+
#else
127+
#undef noexcept
128+
noexcept
129+
#endif
130+
;
131+
)";
132+
105133
return code;
106134
}
107135

toolchain/check/testdata/interop/cpp/function/arithmetic_types_bridged.carbon

Lines changed: 69 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1642,11 +1642,17 @@ fn F() {
16421642
// CHECK:STDOUT: --- import_bool_return.carbon
16431643
// CHECK:STDOUT:
16441644
// CHECK:STDOUT: constants {
1645+
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
16451646
// CHECK:STDOUT: %Bool.type: type = fn_type @Bool [concrete]
16461647
// CHECK:STDOUT: %Bool: %Bool.type = struct_value () [concrete]
16471648
// CHECK:STDOUT: %pattern_type.831: type = pattern_type bool [concrete]
16481649
// CHECK:STDOUT: %foo_bool.type: type = fn_type @foo_bool [concrete]
16491650
// CHECK:STDOUT: %foo_bool: %foo_bool.type = struct_value () [concrete]
1651+
// CHECK:STDOUT: %ptr.bb2: type = ptr_type bool [concrete]
1652+
// CHECK:STDOUT: %foo_bool__carbon_thunk.type: type = fn_type @foo_bool__carbon_thunk [concrete]
1653+
// CHECK:STDOUT: %foo_bool__carbon_thunk: %foo_bool__carbon_thunk.type = struct_value () [concrete]
1654+
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.655: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(bool) [concrete]
1655+
// CHECK:STDOUT: %T.as.Destroy.impl.Op.8b7: %T.as.Destroy.impl.Op.type.655 = struct_value () [concrete]
16501656
// CHECK:STDOUT: }
16511657
// CHECK:STDOUT:
16521658
// CHECK:STDOUT: imports {
@@ -1659,6 +1665,11 @@ fn F() {
16591665
// CHECK:STDOUT: } {
16601666
// CHECK:STDOUT: <elided>
16611667
// CHECK:STDOUT: }
1668+
// CHECK:STDOUT: %foo_bool__carbon_thunk.decl: %foo_bool__carbon_thunk.type = fn_decl @foo_bool__carbon_thunk [concrete = constants.%foo_bool__carbon_thunk] {
1669+
// CHECK:STDOUT: <elided>
1670+
// CHECK:STDOUT: } {
1671+
// CHECK:STDOUT: <elided>
1672+
// CHECK:STDOUT: }
16621673
// CHECK:STDOUT: }
16631674
// CHECK:STDOUT:
16641675
// CHECK:STDOUT: fn @F() {
@@ -1668,26 +1679,40 @@ fn F() {
16681679
// CHECK:STDOUT: }
16691680
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
16701681
// CHECK:STDOUT: %foo_bool.ref: %foo_bool.type = name_ref foo_bool, imports.%foo_bool.decl [concrete = constants.%foo_bool]
1671-
// CHECK:STDOUT: %foo_bool.call: init bool = call %foo_bool.ref()
1682+
// CHECK:STDOUT: %.loc8_30.1: ref bool = temporary_storage
1683+
// CHECK:STDOUT: %addr.loc8_30.1: %ptr.bb2 = addr_of %.loc8_30.1
1684+
// CHECK:STDOUT: %foo_bool__carbon_thunk.call: init %empty_tuple.type = call imports.%foo_bool__carbon_thunk.decl(%addr.loc8_30.1)
1685+
// CHECK:STDOUT: %.loc8_30.2: init bool = in_place_init %foo_bool__carbon_thunk.call, %.loc8_30.1
16721686
// CHECK:STDOUT: %.loc8_10.1: type = splice_block %.loc8_10.3 [concrete = bool] {
16731687
// CHECK:STDOUT: %Bool.call: init type = call constants.%Bool() [concrete = bool]
16741688
// CHECK:STDOUT: %.loc8_10.2: type = value_of_initializer %Bool.call [concrete = bool]
16751689
// CHECK:STDOUT: %.loc8_10.3: type = converted %Bool.call, %.loc8_10.2 [concrete = bool]
16761690
// CHECK:STDOUT: }
1677-
// CHECK:STDOUT: %.loc8_30.1: bool = value_of_initializer %foo_bool.call
1678-
// CHECK:STDOUT: %.loc8_30.2: bool = converted %foo_bool.call, %.loc8_30.1
1679-
// CHECK:STDOUT: %x: bool = bind_name x, %.loc8_30.2
1691+
// CHECK:STDOUT: %.loc8_30.3: bool = value_of_initializer %.loc8_30.2
1692+
// CHECK:STDOUT: %.loc8_30.4: bool = converted %.loc8_30.2, %.loc8_30.3
1693+
// CHECK:STDOUT: %x: bool = bind_name x, %.loc8_30.4
1694+
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc8_30.1, constants.%T.as.Destroy.impl.Op.8b7
1695+
// CHECK:STDOUT: <elided>
1696+
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc8_30.1, %T.as.Destroy.impl.Op.specific_fn
1697+
// CHECK:STDOUT: %addr.loc8_30.2: %ptr.bb2 = addr_of %.loc8_30.1
1698+
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc8_30.2)
16801699
// CHECK:STDOUT: <elided>
16811700
// CHECK:STDOUT: }
16821701
// CHECK:STDOUT:
16831702
// CHECK:STDOUT: --- import_short_return.carbon
16841703
// CHECK:STDOUT:
16851704
// CHECK:STDOUT: constants {
1705+
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
16861706
// CHECK:STDOUT: %int_16: Core.IntLiteral = int_value 16 [concrete]
16871707
// CHECK:STDOUT: %i16: type = class_type @Int, @Int(%int_16) [concrete]
16881708
// CHECK:STDOUT: %pattern_type.2f8: type = pattern_type %i16 [concrete]
16891709
// CHECK:STDOUT: %foo_short.type: type = fn_type @foo_short [concrete]
16901710
// CHECK:STDOUT: %foo_short: %foo_short.type = struct_value () [concrete]
1711+
// CHECK:STDOUT: %ptr.251: type = ptr_type %i16 [concrete]
1712+
// CHECK:STDOUT: %foo_short__carbon_thunk.type: type = fn_type @foo_short__carbon_thunk [concrete]
1713+
// CHECK:STDOUT: %foo_short__carbon_thunk: %foo_short__carbon_thunk.type = struct_value () [concrete]
1714+
// CHECK:STDOUT: %Int.as.Destroy.impl.Op.type.613: type = fn_type @Int.as.Destroy.impl.Op, @Int.as.Destroy.impl(%int_16) [concrete]
1715+
// CHECK:STDOUT: %Int.as.Destroy.impl.Op.536: %Int.as.Destroy.impl.Op.type.613 = struct_value () [concrete]
16911716
// CHECK:STDOUT: }
16921717
// CHECK:STDOUT:
16931718
// CHECK:STDOUT: imports {
@@ -1700,6 +1725,11 @@ fn F() {
17001725
// CHECK:STDOUT: } {
17011726
// CHECK:STDOUT: <elided>
17021727
// CHECK:STDOUT: }
1728+
// CHECK:STDOUT: %foo_short__carbon_thunk.decl: %foo_short__carbon_thunk.type = fn_decl @foo_short__carbon_thunk [concrete = constants.%foo_short__carbon_thunk] {
1729+
// CHECK:STDOUT: <elided>
1730+
// CHECK:STDOUT: } {
1731+
// CHECK:STDOUT: <elided>
1732+
// CHECK:STDOUT: }
17031733
// CHECK:STDOUT: }
17041734
// CHECK:STDOUT:
17051735
// CHECK:STDOUT: fn @F() {
@@ -1709,14 +1739,22 @@ fn F() {
17091739
// CHECK:STDOUT: }
17101740
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
17111741
// CHECK:STDOUT: %foo_short.ref: %foo_short.type = name_ref foo_short, imports.%foo_short.decl [concrete = constants.%foo_short]
1712-
// CHECK:STDOUT: %foo_short.call: init %i16 = call %foo_short.ref()
1742+
// CHECK:STDOUT: %.loc8_30.1: ref %i16 = temporary_storage
1743+
// CHECK:STDOUT: %addr.loc8_30.1: %ptr.251 = addr_of %.loc8_30.1
1744+
// CHECK:STDOUT: %foo_short__carbon_thunk.call: init %empty_tuple.type = call imports.%foo_short__carbon_thunk.decl(%addr.loc8_30.1)
1745+
// CHECK:STDOUT: %.loc8_30.2: init %i16 = in_place_init %foo_short__carbon_thunk.call, %.loc8_30.1
17131746
// CHECK:STDOUT: %.loc8_10: type = splice_block %i16 [concrete = constants.%i16] {
17141747
// CHECK:STDOUT: %int_16: Core.IntLiteral = int_value 16 [concrete = constants.%int_16]
17151748
// CHECK:STDOUT: %i16: type = class_type @Int, @Int(constants.%int_16) [concrete = constants.%i16]
17161749
// CHECK:STDOUT: }
1717-
// CHECK:STDOUT: %.loc8_30.1: %i16 = value_of_initializer %foo_short.call
1718-
// CHECK:STDOUT: %.loc8_30.2: %i16 = converted %foo_short.call, %.loc8_30.1
1719-
// CHECK:STDOUT: %x: %i16 = bind_name x, %.loc8_30.2
1750+
// CHECK:STDOUT: %.loc8_30.3: %i16 = value_of_initializer %.loc8_30.2
1751+
// CHECK:STDOUT: %.loc8_30.4: %i16 = converted %.loc8_30.2, %.loc8_30.3
1752+
// CHECK:STDOUT: %x: %i16 = bind_name x, %.loc8_30.4
1753+
// CHECK:STDOUT: %Int.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc8_30.1, constants.%Int.as.Destroy.impl.Op.536
1754+
// CHECK:STDOUT: <elided>
1755+
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc8_30.1, %Int.as.Destroy.impl.Op.specific_fn
1756+
// CHECK:STDOUT: %addr.loc8_30.2: %ptr.251 = addr_of %.loc8_30.1
1757+
// CHECK:STDOUT: %Int.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc8_30.2)
17201758
// CHECK:STDOUT: <elided>
17211759
// CHECK:STDOUT: }
17221760
// CHECK:STDOUT:
@@ -1744,11 +1782,17 @@ fn F() {
17441782
// CHECK:STDOUT: --- import_double_return.carbon
17451783
// CHECK:STDOUT:
17461784
// CHECK:STDOUT: constants {
1785+
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
17471786
// CHECK:STDOUT: %int_64: Core.IntLiteral = int_value 64 [concrete]
17481787
// CHECK:STDOUT: %f64.d77: type = class_type @Float, @Float(%int_64) [concrete]
17491788
// CHECK:STDOUT: %pattern_type.0ae: type = pattern_type %f64.d77 [concrete]
17501789
// CHECK:STDOUT: %foo_double.type: type = fn_type @foo_double [concrete]
17511790
// CHECK:STDOUT: %foo_double: %foo_double.type = struct_value () [concrete]
1791+
// CHECK:STDOUT: %ptr.bcc: type = ptr_type %f64.d77 [concrete]
1792+
// CHECK:STDOUT: %foo_double__carbon_thunk.type: type = fn_type @foo_double__carbon_thunk [concrete]
1793+
// CHECK:STDOUT: %foo_double__carbon_thunk: %foo_double__carbon_thunk.type = struct_value () [concrete]
1794+
// CHECK:STDOUT: %Float.as.Destroy.impl.Op.type.cd5: type = fn_type @Float.as.Destroy.impl.Op, @Float.as.Destroy.impl(%int_64) [concrete]
1795+
// CHECK:STDOUT: %Float.as.Destroy.impl.Op.b8c: %Float.as.Destroy.impl.Op.type.cd5 = struct_value () [concrete]
17521796
// CHECK:STDOUT: }
17531797
// CHECK:STDOUT:
17541798
// CHECK:STDOUT: imports {
@@ -1761,6 +1805,11 @@ fn F() {
17611805
// CHECK:STDOUT: } {
17621806
// CHECK:STDOUT: <elided>
17631807
// CHECK:STDOUT: }
1808+
// CHECK:STDOUT: %foo_double__carbon_thunk.decl: %foo_double__carbon_thunk.type = fn_decl @foo_double__carbon_thunk [concrete = constants.%foo_double__carbon_thunk] {
1809+
// CHECK:STDOUT: <elided>
1810+
// CHECK:STDOUT: } {
1811+
// CHECK:STDOUT: <elided>
1812+
// CHECK:STDOUT: }
17641813
// CHECK:STDOUT: }
17651814
// CHECK:STDOUT:
17661815
// CHECK:STDOUT: fn @F() {
@@ -1770,14 +1819,22 @@ fn F() {
17701819
// CHECK:STDOUT: }
17711820
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
17721821
// CHECK:STDOUT: %foo_double.ref: %foo_double.type = name_ref foo_double, imports.%foo_double.decl [concrete = constants.%foo_double]
1773-
// CHECK:STDOUT: %foo_double.call: init %f64.d77 = call %foo_double.ref()
1822+
// CHECK:STDOUT: %.loc8_31.1: ref %f64.d77 = temporary_storage
1823+
// CHECK:STDOUT: %addr.loc8_31.1: %ptr.bcc = addr_of %.loc8_31.1
1824+
// CHECK:STDOUT: %foo_double__carbon_thunk.call: init %empty_tuple.type = call imports.%foo_double__carbon_thunk.decl(%addr.loc8_31.1)
1825+
// CHECK:STDOUT: %.loc8_31.2: init %f64.d77 = in_place_init %foo_double__carbon_thunk.call, %.loc8_31.1
17741826
// CHECK:STDOUT: %.loc8_10: type = splice_block %f64 [concrete = constants.%f64.d77] {
17751827
// CHECK:STDOUT: %int_64: Core.IntLiteral = int_value 64 [concrete = constants.%int_64]
17761828
// CHECK:STDOUT: %f64: type = class_type @Float, @Float(constants.%int_64) [concrete = constants.%f64.d77]
17771829
// CHECK:STDOUT: }
1778-
// CHECK:STDOUT: %.loc8_31.1: %f64.d77 = value_of_initializer %foo_double.call
1779-
// CHECK:STDOUT: %.loc8_31.2: %f64.d77 = converted %foo_double.call, %.loc8_31.1
1780-
// CHECK:STDOUT: %x: %f64.d77 = bind_name x, %.loc8_31.2
1830+
// CHECK:STDOUT: %.loc8_31.3: %f64.d77 = value_of_initializer %.loc8_31.2
1831+
// CHECK:STDOUT: %.loc8_31.4: %f64.d77 = converted %.loc8_31.2, %.loc8_31.3
1832+
// CHECK:STDOUT: %x: %f64.d77 = bind_name x, %.loc8_31.4
1833+
// CHECK:STDOUT: %Float.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc8_31.1, constants.%Float.as.Destroy.impl.Op.b8c
1834+
// CHECK:STDOUT: <elided>
1835+
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc8_31.1, %Float.as.Destroy.impl.Op.specific_fn
1836+
// CHECK:STDOUT: %addr.loc8_31.2: %ptr.bcc = addr_of %.loc8_31.1
1837+
// CHECK:STDOUT: %Float.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc8_31.2)
17811838
// CHECK:STDOUT: <elided>
17821839
// CHECK:STDOUT: }
17831840
// CHECK:STDOUT:

toolchain/check/testdata/interop/cpp/function/class.carbon

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -447,13 +447,29 @@ auto foo() -> C;
447447

448448
library "[[@TEST_NAME]]";
449449

450+
// CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE+12]]:10: in file included here [InCppInclude]
451+
// CHECK:STDERR: ./decl_value_return_type.h:4:6: error: calling 'foo' with incomplete return type 'C' [CppInteropParseError]
452+
// CHECK:STDERR: 4 | auto foo() -> C;
453+
// CHECK:STDERR: | ^~~
454+
// CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE+8]]:10: in file included here [InCppInclude]
455+
// CHECK:STDERR: ./decl_value_return_type.h:4:6: note: 'foo' declared here [CppInteropParseNote]
456+
// CHECK:STDERR: 4 | auto foo() -> C;
457+
// CHECK:STDERR: | ^
458+
// CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE+4]]:10: in file included here [InCppInclude]
459+
// CHECK:STDERR: ./decl_value_return_type.h:2:7: note: forward declaration of 'C' [CppInteropParseNote]
460+
// CHECK:STDERR: 2 | class C;
461+
// CHECK:STDERR: | ^
450462
import Cpp library "decl_value_return_type.h";
451463

452464
fn F() {
465+
// CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE+13]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
466+
// CHECK:STDERR: Cpp.foo();
467+
// CHECK:STDERR: ^~~~~~~
468+
// CHECK:STDERR:
453469
// CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE+9]]:3: error: function returns incomplete type `Cpp.C` [IncompleteTypeInFunctionReturnType]
454470
// CHECK:STDERR: Cpp.foo();
455471
// CHECK:STDERR: ^~~~~~~~~
456-
// CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE-6]]:10: in file included here [InCppInclude]
472+
// CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE-10]]:10: in file included here [InCppInclude]
457473
// CHECK:STDERR: ./decl_value_return_type.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere]
458474
// CHECK:STDERR: class C;
459475
// CHECK:STDERR: ^
@@ -1157,9 +1173,11 @@ fn F() {
11571173
// CHECK:STDOUT: %C: type = class_type @C [concrete]
11581174
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
11591175
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
1176+
// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete]
1177+
// CHECK:STDOUT: %foo__carbon_thunk.type: type = fn_type @foo__carbon_thunk [concrete]
1178+
// CHECK:STDOUT: %foo__carbon_thunk: %foo__carbon_thunk.type = struct_value () [concrete]
11601179
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.1b3: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete]
11611180
// CHECK:STDOUT: %T.as.Destroy.impl.Op.21b: %T.as.Destroy.impl.Op.type.1b3 = struct_value () [concrete]
1162-
// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete]
11631181
// CHECK:STDOUT: }
11641182
// CHECK:STDOUT:
11651183
// CHECK:STDOUT: imports {
@@ -1172,20 +1190,27 @@ fn F() {
11721190
// CHECK:STDOUT: } {
11731191
// CHECK:STDOUT: <elided>
11741192
// CHECK:STDOUT: }
1193+
// CHECK:STDOUT: %foo__carbon_thunk.decl: %foo__carbon_thunk.type = fn_decl @foo__carbon_thunk [concrete = constants.%foo__carbon_thunk] {
1194+
// CHECK:STDOUT: <elided>
1195+
// CHECK:STDOUT: } {
1196+
// CHECK:STDOUT: <elided>
1197+
// CHECK:STDOUT: }
11751198
// CHECK:STDOUT: }
11761199
// CHECK:STDOUT:
11771200
// CHECK:STDOUT: fn @F() {
11781201
// CHECK:STDOUT: !entry:
11791202
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
11801203
// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo]
11811204
// CHECK:STDOUT: %.loc8_11.1: ref %C = temporary_storage
1182-
// CHECK:STDOUT: %foo.call: init %C = call %foo.ref() to %.loc8_11.1
1183-
// CHECK:STDOUT: %.loc8_11.2: ref %C = temporary %.loc8_11.1, %foo.call
1205+
// CHECK:STDOUT: %addr.loc8_11.1: %ptr.d9e = addr_of %.loc8_11.1
1206+
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_11.1)
1207+
// CHECK:STDOUT: %.loc8_11.2: init %C = in_place_init %foo__carbon_thunk.call, %.loc8_11.1
1208+
// CHECK:STDOUT: %.loc8_11.3: ref %C = temporary %.loc8_11.1, %.loc8_11.2
11841209
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc8_11.1, constants.%T.as.Destroy.impl.Op.21b
11851210
// CHECK:STDOUT: <elided>
11861211
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc8_11.1, %T.as.Destroy.impl.Op.specific_fn
1187-
// CHECK:STDOUT: %addr: %ptr.d9e = addr_of %.loc8_11.1
1188-
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr)
1212+
// CHECK:STDOUT: %addr.loc8_11.2: %ptr.d9e = addr_of %.loc8_11.1
1213+
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc8_11.2)
11891214
// CHECK:STDOUT: <elided>
11901215
// CHECK:STDOUT: }
11911216
// CHECK:STDOUT:

0 commit comments

Comments
 (0)