Skip to content

Commit db0a00d

Browse files
authored
Fix double-destruction of temporaries. (#6010)
Attach the cleanup to the `Temporary` instruction instead of to the `TemporaryStorage` instruction. We create `TemporaryStorage` instructions speculatively when creating an initializing expression, and may overwrite those instructions with other instructions if it turns out that a temporary is not required. Instead, wait until we finalize the temporary and create a `Temporary` instruction to register the cleanup.
1 parent f943f31 commit db0a00d

File tree

102 files changed

+1139
-1659
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+1139
-1659
lines changed

toolchain/check/call.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ static auto PerformCallToFunction(Context& context, SemIR::LocId loc_id,
230230
case SemIR::InitRepr::InPlace:
231231
// Tentatively put storage for a temporary in the function's return slot.
232232
// This will be replaced if necessary when we perform initialization.
233-
return_slot_arg_id = AddInstWithCleanup<SemIR::TemporaryStorage>(
233+
return_slot_arg_id = AddInst<SemIR::TemporaryStorage>(
234234
context, loc_id, {.type_id = return_info.type_id});
235235
break;
236236
case SemIR::InitRepr::None:

toolchain/check/convert.cpp

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,12 @@ static auto CopyValueToTemporary(Context& context, SemIR::InstId init_id)
6363
// TODO: Consider using `None` to mean that we immediately materialize and
6464
// initialize a temporary, rather than two separate instructions.
6565
auto init = context.sem_ir().insts().Get(init_id);
66-
auto temporary_id = AddInstWithCleanup<SemIR::TemporaryStorage>(
66+
auto temporary_id = AddInst<SemIR::TemporaryStorage>(
6767
context, SemIR::LocId(init_id), {.type_id = init.type_id()});
68-
return AddInst<SemIR::Temporary>(context, SemIR::LocId(init_id),
69-
{.type_id = init.type_id(),
70-
.storage_id = temporary_id,
71-
.init_id = init_id});
68+
return AddInstWithCleanup<SemIR::Temporary>(context, SemIR::LocId(init_id),
69+
{.type_id = init.type_id(),
70+
.storage_id = temporary_id,
71+
.init_id = init_id});
7272
}
7373

7474
// Commits to using a temporary to store the result of the initializing
@@ -88,10 +88,11 @@ static auto FinalizeTemporary(Context& context, SemIR::InstId init_id,
8888
"initialized multiple times? Have {0}",
8989
sem_ir.insts().Get(return_slot_arg_id));
9090
auto init = sem_ir.insts().Get(init_id);
91-
return AddInst<SemIR::Temporary>(context, SemIR::LocId(init_id),
92-
{.type_id = init.type_id(),
93-
.storage_id = return_slot_arg_id,
94-
.init_id = init_id});
91+
return AddInstWithCleanup<SemIR::Temporary>(
92+
context, SemIR::LocId(init_id),
93+
{.type_id = init.type_id(),
94+
.storage_id = return_slot_arg_id,
95+
.init_id = init_id});
9596
}
9697

9798
if (discarded) {
@@ -261,9 +262,8 @@ static auto ConvertTupleToArray(Context& context, SemIR::TupleType tuple_type,
261262
// destination for the array initialization if we weren't given one.
262263
SemIR::InstId return_slot_arg_id = target.init_id;
263264
if (!target.init_id.has_value()) {
264-
return_slot_arg_id =
265-
target_block->AddInstWithCleanup<SemIR::TemporaryStorage>(
266-
value_loc_id, {.type_id = target.type_id});
265+
return_slot_arg_id = target_block->AddInst<SemIR::TemporaryStorage>(
266+
value_loc_id, {.type_id = target.type_id});
267267
}
268268

269269
// Initialize each element of the array from the corresponding element of the
@@ -607,7 +607,7 @@ static auto ConvertStructToClass(Context& context, SemIR::StructType src_type,
607607
if (need_temporary) {
608608
target.kind = ConversionTarget::Initializer;
609609
target.init_block = &target_block;
610-
target.init_id = target_block.AddInstWithCleanup<SemIR::TemporaryStorage>(
610+
target.init_id = target_block.AddInst<SemIR::TemporaryStorage>(
611611
SemIR::LocId(value_id), {.type_id = target.type_id});
612612
}
613613

@@ -617,10 +617,11 @@ static auto ConvertStructToClass(Context& context, SemIR::StructType src_type,
617617

618618
if (need_temporary) {
619619
target_block.InsertHere();
620-
result_id = AddInst<SemIR::Temporary>(context, SemIR::LocId(value_id),
621-
{.type_id = target.type_id,
622-
.storage_id = target.init_id,
623-
.init_id = result_id});
620+
result_id =
621+
AddInstWithCleanup<SemIR::Temporary>(context, SemIR::LocId(value_id),
622+
{.type_id = target.type_id,
623+
.storage_id = target.init_id,
624+
.init_id = result_id});
624625
}
625626
return result_id;
626627
}

toolchain/check/cpp_thunk.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,7 @@ auto PerformCppThunkCall(Context& context, SemIR::LocId loc_id,
600600
if (thunk_takes_return_address) {
601601
// Create a temporary if the caller didn't provide a return slot.
602602
if (!return_slot_id.has_value()) {
603-
return_slot_id = AddInstWithCleanup<SemIR::TemporaryStorage>(
603+
return_slot_id = AddInst<SemIR::TemporaryStorage>(
604604
context, loc_id, {.type_id = return_type_id});
605605
}
606606

toolchain/check/pattern_match.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ auto MatchContext::DoEmitPatternMatch(Context& context,
281281
context.emitter().Emit(entry.scrutinee_id, AddrSelfIsNonRef);
282282
// Add fake reference expression to preserve invariants.
283283
auto scrutinee = context.insts().GetWithLocId(entry.scrutinee_id);
284-
scrutinee_ref_id = AddInstWithCleanup<SemIR::TemporaryStorage>(
284+
scrutinee_ref_id = AddInst<SemIR::TemporaryStorage>(
285285
context, scrutinee.loc_id, {.type_id = scrutinee.inst.type_id()});
286286
}
287287
auto scrutinee_ref = context.insts().Get(scrutinee_ref_id);
@@ -480,7 +480,7 @@ auto MatchContext::DoEmitPatternMatch(Context& context,
480480
break;
481481
}
482482
case MatchKind::Caller: {
483-
storage_id = AddInstWithCleanup<SemIR::TemporaryStorage>(
483+
storage_id = AddInst<SemIR::TemporaryStorage>(
484484
context, SemIR::LocId(pattern_inst_id),
485485
{.type_id =
486486
ExtractScrutineeType(context.sem_ir(), var_pattern.type_id)});
@@ -497,10 +497,23 @@ auto MatchContext::DoEmitPatternMatch(Context& context,
497497
if (entry.scrutinee_id.has_value()) {
498498
auto init_id = Initialize(context, SemIR::LocId(pattern_inst_id),
499499
storage_id, entry.scrutinee_id);
500-
// TODO: Consider using different instruction kinds for assignment
501-
// versus initialization.
502-
AddInst<SemIR::Assign>(context, SemIR::LocId(pattern_inst_id),
503-
{.lhs_id = storage_id, .rhs_id = init_id});
500+
// If we created a `TemporaryStorage` to hold the var, create a
501+
// corresponding `Temporary` to model that its initialization is complete.
502+
// TODO: If the subpattern is a binding, we may want to destroy the
503+
// parameter variable in the callee instead of the caller so that we can
504+
// support destructive move from it.
505+
if (kind_ == MatchKind::Caller) {
506+
storage_id = AddInstWithCleanup<SemIR::Temporary>(
507+
context, SemIR::LocId(pattern_inst_id),
508+
{.type_id = context.insts().Get(storage_id).type_id(),
509+
.storage_id = storage_id,
510+
.init_id = init_id});
511+
} else {
512+
// TODO: Consider using different instruction kinds for assignment
513+
// versus initialization.
514+
AddInst<SemIR::Assign>(context, SemIR::LocId(pattern_inst_id),
515+
{.lhs_id = storage_id, .rhs_id = init_id});
516+
}
504517
}
505518
AddWork({.pattern_id = var_pattern.subpattern_id,
506519
.scrutinee_id = storage_id,

toolchain/check/testdata/array/basics.carbon

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,6 @@ var a: array(1, 1);
181181
// CHECK:STDOUT: %tuple.type.14a: type = tuple_type (%tuple.type.734, %tuple.type.734) [concrete]
182182
// CHECK:STDOUT: %int_0: Core.IntLiteral = int_value 0 [concrete]
183183
// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete]
184-
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.fe9: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%tuple.type.734) [concrete]
185-
// CHECK:STDOUT: %T.as.Destroy.impl.Op.ae1: %T.as.Destroy.impl.Op.type.fe9 = struct_value () [concrete]
186-
// CHECK:STDOUT: %ptr.dbe: type = ptr_type %tuple.type.734 [concrete]
187184
// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.280: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%array_type) [concrete]
188185
// CHECK:STDOUT: %T.as.Destroy.impl.Op.d4f: %T.as.Destroy.impl.Op.type.280 = struct_value () [concrete]
189186
// CHECK:STDOUT: }
@@ -224,21 +221,11 @@ var a: array(1, 1);
224221
// CHECK:STDOUT: %array_type: type = array_type %int_2, %.loc10_24.2 [concrete = constants.%array_type]
225222
// CHECK:STDOUT: }
226223
// CHECK:STDOUT: %v: ref %array_type = bind_name v, %v.var
227-
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc10_41.1: <bound method> = bound_method %.loc10_41.2, constants.%T.as.Destroy.impl.Op.ae1
224+
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %v.var, constants.%T.as.Destroy.impl.Op.d4f
228225
// CHECK:STDOUT: <elided>
229-
// CHECK:STDOUT: %bound_method.loc10_41.1: <bound method> = bound_method %.loc10_41.2, %T.as.Destroy.impl.Op.specific_fn.1
230-
// CHECK:STDOUT: %addr.loc10_41.1: %ptr.dbe = addr_of %.loc10_41.2
231-
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc10_41.1: init %empty_tuple.type = call %bound_method.loc10_41.1(%addr.loc10_41.1)
232-
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc10_41.2: <bound method> = bound_method %.loc10_41.1, constants.%T.as.Destroy.impl.Op.ae1
233-
// CHECK:STDOUT: <elided>
234-
// CHECK:STDOUT: %bound_method.loc10_41.2: <bound method> = bound_method %.loc10_41.1, %T.as.Destroy.impl.Op.specific_fn.2
235-
// CHECK:STDOUT: %addr.loc10_41.2: %ptr.dbe = addr_of %.loc10_41.1
236-
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc10_41.2: init %empty_tuple.type = call %bound_method.loc10_41.2(%addr.loc10_41.2)
237-
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc10_3: <bound method> = bound_method %v.var, constants.%T.as.Destroy.impl.Op.d4f
238-
// CHECK:STDOUT: <elided>
239-
// CHECK:STDOUT: %bound_method.loc10_3: <bound method> = bound_method %v.var, %T.as.Destroy.impl.Op.specific_fn.3
240-
// CHECK:STDOUT: %addr.loc10_3: %ptr.c6b = addr_of %v.var
241-
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc10_3: init %empty_tuple.type = call %bound_method.loc10_3(%addr.loc10_3)
226+
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %v.var, %T.as.Destroy.impl.Op.specific_fn
227+
// CHECK:STDOUT: %addr: %ptr.c6b = addr_of %v.var
228+
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr)
242229
// CHECK:STDOUT: <elided>
243230
// CHECK:STDOUT: }
244231
// CHECK:STDOUT:
@@ -355,10 +342,10 @@ var a: array(1, 1);
355342
// CHECK:STDOUT: %array_type: type = array_type %int_1, %.loc8_17.2 [concrete = constants.%array_type]
356343
// CHECK:STDOUT: }
357344
// CHECK:STDOUT: %t: ref %array_type = bind_name t, %t.var
358-
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_27: <bound method> = bound_method %.loc8_27.1, constants.%T.as.Destroy.impl.Op.f19
345+
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_27: <bound method> = bound_method %.loc8_27.2, constants.%T.as.Destroy.impl.Op.f19
359346
// CHECK:STDOUT: <elided>
360-
// CHECK:STDOUT: %bound_method.loc8_27: <bound method> = bound_method %.loc8_27.1, %T.as.Destroy.impl.Op.specific_fn.1
361-
// CHECK:STDOUT: %addr.loc8_27: %ptr.652 = addr_of %.loc8_27.1
347+
// CHECK:STDOUT: %bound_method.loc8_27: <bound method> = bound_method %.loc8_27.2, %T.as.Destroy.impl.Op.specific_fn.1
348+
// CHECK:STDOUT: %addr.loc8_27: %ptr.652 = addr_of %.loc8_27.2
362349
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_27: init %empty_tuple.type = call %bound_method.loc8_27(%addr.loc8_27)
363350
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_3: <bound method> = bound_method %t.var, constants.%T.as.Destroy.impl.Op.688
364351
// CHECK:STDOUT: <elided>

toolchain/check/testdata/array/import.carbon

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,10 @@ fn F() -> array(i32, 1) {
8787
// CHECK:STDOUT: %i32.loc6: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
8888
// CHECK:STDOUT: %.loc6_15.1: ref %i32 = array_index %.loc6_12.2, %n.ref
8989
// CHECK:STDOUT: %.loc6_15.2: %i32 = bind_value %.loc6_15.1
90-
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc6_12.1, constants.%T.as.Destroy.impl.Op.552
90+
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc6_12.2, constants.%T.as.Destroy.impl.Op.552
9191
// CHECK:STDOUT: <elided>
92-
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc6_12.1, %T.as.Destroy.impl.Op.specific_fn
93-
// CHECK:STDOUT: %addr: %ptr.830 = addr_of %.loc6_12.1
92+
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %.loc6_12.2, %T.as.Destroy.impl.Op.specific_fn
93+
// CHECK:STDOUT: %addr: %ptr.830 = addr_of %.loc6_12.2
9494
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr)
9595
// CHECK:STDOUT: return %.loc6_15.2
9696
// CHECK:STDOUT: }

toolchain/check/testdata/array/index_not_literal.carbon

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,10 @@ fn F(a: array({}, 3)) -> {} {
153153
// CHECK:STDOUT: %F.call: init %i32 = call %F.ref(%.loc10_20.15, %.loc10_23.2)
154154
// CHECK:STDOUT: %.loc10_25.1: %i32 = value_of_initializer %F.call
155155
// CHECK:STDOUT: %.loc10_25.2: %i32 = converted %F.call, %.loc10_25.1
156-
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc10_20.3, constants.%T.as.Destroy.impl.Op.f0b
156+
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %.loc10_20.14, constants.%T.as.Destroy.impl.Op.f0b
157157
// CHECK:STDOUT: <elided>
158-
// CHECK:STDOUT: %bound_method.loc10_20.7: <bound method> = bound_method %.loc10_20.3, %T.as.Destroy.impl.Op.specific_fn
159-
// CHECK:STDOUT: %addr: %ptr.f01 = addr_of %.loc10_20.3
158+
// CHECK:STDOUT: %bound_method.loc10_20.7: <bound method> = bound_method %.loc10_20.14, %T.as.Destroy.impl.Op.specific_fn
159+
// CHECK:STDOUT: %addr: %ptr.f01 = addr_of %.loc10_20.14
160160
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method.loc10_20.7(%addr)
161161
// CHECK:STDOUT: return %.loc10_25.2
162162
// CHECK:STDOUT: }

toolchain/check/testdata/as/basics.carbon

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -249,11 +249,11 @@ let n: {.x: ()} = {.x = ()} as {.x = ()};
249249
// CHECK:STDOUT: %tuple: %tuple.type.b67 = tuple_value (%.loc13_25.3, %.loc13_33.3)
250250
// CHECK:STDOUT: %.loc13_34.2: %tuple.type.b67 = converted %.loc13_34.1, %tuple
251251
// CHECK:STDOUT: %a: %tuple.type.b67 = bind_name a, %.loc13_34.2
252-
// CHECK:STDOUT: %X.as.Destroy.impl.Op.bound.loc13_33: <bound method> = bound_method %.loc13_33.1, constants.%X.as.Destroy.impl.Op
253-
// CHECK:STDOUT: %addr.loc13_33: %ptr.d17 = addr_of %.loc13_33.1
252+
// CHECK:STDOUT: %X.as.Destroy.impl.Op.bound.loc13_33: <bound method> = bound_method %.loc13_33.2, constants.%X.as.Destroy.impl.Op
253+
// CHECK:STDOUT: %addr.loc13_33: %ptr.d17 = addr_of %.loc13_33.2
254254
// CHECK:STDOUT: %X.as.Destroy.impl.Op.call.loc13_33: init %empty_tuple.type = call %X.as.Destroy.impl.Op.bound.loc13_33(%addr.loc13_33)
255-
// CHECK:STDOUT: %X.as.Destroy.impl.Op.bound.loc13_25: <bound method> = bound_method %.loc13_25.1, constants.%X.as.Destroy.impl.Op
256-
// CHECK:STDOUT: %addr.loc13_25: %ptr.d17 = addr_of %.loc13_25.1
255+
// CHECK:STDOUT: %X.as.Destroy.impl.Op.bound.loc13_25: <bound method> = bound_method %.loc13_25.2, constants.%X.as.Destroy.impl.Op
256+
// CHECK:STDOUT: %addr.loc13_25: %ptr.d17 = addr_of %.loc13_25.2
257257
// CHECK:STDOUT: %X.as.Destroy.impl.Op.call.loc13_25: init %empty_tuple.type = call %X.as.Destroy.impl.Op.bound.loc13_25(%addr.loc13_25)
258258
// CHECK:STDOUT: <elided>
259259
// CHECK:STDOUT: }
@@ -286,17 +286,11 @@ let n: {.x: ()} = {.x = ()} as {.x = ()};
286286
// CHECK:STDOUT: %.loc20_15.3: type = converted %.loc20_15.2, constants.%tuple.type.b67 [concrete = constants.%tuple.type.b67]
287287
// CHECK:STDOUT: }
288288
// CHECK:STDOUT: %b: ref %tuple.type.b67 = bind_name b, %b.var
289-
// CHECK:STDOUT: %X.as.Destroy.impl.Op.bound.loc20_34.1: <bound method> = bound_method %tuple.elem1, constants.%X.as.Destroy.impl.Op
290-
// CHECK:STDOUT: %addr.loc20_34.1: %ptr.d17 = addr_of %tuple.elem1
291-
// CHECK:STDOUT: %X.as.Destroy.impl.Op.call.loc20_34.1: init %empty_tuple.type = call %X.as.Destroy.impl.Op.bound.loc20_34.1(%addr.loc20_34.1)
292-
// CHECK:STDOUT: %X.as.Destroy.impl.Op.bound.loc20_34.2: <bound method> = bound_method %tuple.elem0, constants.%X.as.Destroy.impl.Op
293-
// CHECK:STDOUT: %addr.loc20_34.2: %ptr.d17 = addr_of %tuple.elem0
294-
// CHECK:STDOUT: %X.as.Destroy.impl.Op.call.loc20_34.2: init %empty_tuple.type = call %X.as.Destroy.impl.Op.bound.loc20_34.2(%addr.loc20_34.2)
295289
// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: <bound method> = bound_method %b.var, constants.%T.as.Destroy.impl.Op.279
296290
// CHECK:STDOUT: <elided>
297291
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %b.var, %T.as.Destroy.impl.Op.specific_fn
298-
// CHECK:STDOUT: %addr.loc20_3: %ptr.120 = addr_of %b.var
299-
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc20_3)
292+
// CHECK:STDOUT: %addr: %ptr.120 = addr_of %b.var
293+
// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr)
300294
// CHECK:STDOUT: <elided>
301295
// CHECK:STDOUT: }
302296
// CHECK:STDOUT:
@@ -360,12 +354,9 @@ let n: {.x: ()} = {.x = ()} as {.x = ()};
360354
// CHECK:STDOUT: assign %x.var, %Make.call
361355
// CHECK:STDOUT: %X.ref.loc24_10: type = name_ref X, file.%X.decl [concrete = constants.%X]
362356
// CHECK:STDOUT: %x: ref %X = bind_name x, %x.var
363-
// CHECK:STDOUT: %X.as.Destroy.impl.Op.bound.loc24_3.1: <bound method> = bound_method %.loc24, constants.%X.as.Destroy.impl.Op
364-
// CHECK:STDOUT: %addr.loc24_3.1: %ptr.d17 = addr_of %.loc24
365-
// CHECK:STDOUT: %X.as.Destroy.impl.Op.call.loc24_3.1: init %empty_tuple.type = call %X.as.Destroy.impl.Op.bound.loc24_3.1(%addr.loc24_3.1)
366-
// CHECK:STDOUT: %X.as.Destroy.impl.Op.bound.loc24_3.2: <bound method> = bound_method %x.var, constants.%X.as.Destroy.impl.Op
367-
// CHECK:STDOUT: %addr.loc24_3.2: %ptr.d17 = addr_of %x.var
368-
// CHECK:STDOUT: %X.as.Destroy.impl.Op.call.loc24_3.2: init %empty_tuple.type = call %X.as.Destroy.impl.Op.bound.loc24_3.2(%addr.loc24_3.2)
357+
// CHECK:STDOUT: %X.as.Destroy.impl.Op.bound: <bound method> = bound_method %x.var, constants.%X.as.Destroy.impl.Op
358+
// CHECK:STDOUT: %addr: %ptr.d17 = addr_of %x.var
359+
// CHECK:STDOUT: %X.as.Destroy.impl.Op.call: init %empty_tuple.type = call %X.as.Destroy.impl.Op.bound(%addr)
369360
// CHECK:STDOUT: <elided>
370361
// CHECK:STDOUT: }
371362
// CHECK:STDOUT:

0 commit comments

Comments
 (0)