From e530421ba1c0ba60d8c723e0ee15f7dc079a0898 Mon Sep 17 00:00:00 2001 From: Christopher Di Bella Date: Mon, 28 Sep 2026 22:30:56 +0000 Subject: [PATCH] Make all generated `Destroy.SelfDestruct` calls have desugared `LocId`s (#7855) We use `LocId`s to refer to physical locations in source code. Those don't exist for toolchain-generated entities, so we instead choose a related location that can stand in for a physical location. This inlines the generated entities' constants into their points of use, and reduces the total amount of generated SemIR. This is especially important for calls to `Destroy.SelfDestruct` because these are automatically generated when any destroyable object reaches the end its lifetime. --- toolchain/check/control_flow.cpp | 3 +-- toolchain/check/operator.cpp | 7 ++++--- toolchain/check/operator.h | 4 ++-- .../cpp/function/export/generic.carbon | 19 ++++--------------- toolchain/check/thunk.cpp | 2 +- 5 files changed, 12 insertions(+), 23 deletions(-) diff --git a/toolchain/check/control_flow.cpp b/toolchain/check/control_flow.cpp index 51fca32d08a7..2c95e4e937c8 100644 --- a/toolchain/check/control_flow.cpp +++ b/toolchain/check/control_flow.cpp @@ -155,8 +155,7 @@ static auto AddCleanups(Context& context, ScopeStack::CleanupScopeDepth depth) // TODO: This does the `Destroy` lookup and call at every cleanup block. // Control flow can lead to the same variable being destroyed by multiple // cleanup blocks, so we'll want to avoid this in the future. - BuildSelfDestructCall( - context, context.insts().GetLocIdForDesugaring(destroy_id), destroy_id); + BuildSelfDestructCall(context, destroy_id); } } diff --git a/toolchain/check/operator.cpp b/toolchain/check/operator.cpp index 5029d8132690..9a448911a404 100644 --- a/toolchain/check/operator.cpp +++ b/toolchain/check/operator.cpp @@ -103,9 +103,10 @@ auto BuildUnaryOperator(Context& context, SemIR::LocId loc_id, Operator op, /*is_desugared=*/true); } -auto BuildSelfDestructCall(Context& context, SemIR::LocId loc_id, - SemIR::InstId object_id) -> SemIR::InstId { - return BuildUnaryOperator(context, loc_id, +auto BuildSelfDestructCall(Context& context, SemIR::InstId object_id) + -> SemIR::InstId { + return BuildUnaryOperator(context, + context.insts().GetLocIdForDesugaring(object_id), {.interface_name = CoreIdentifier::Destroy, .op_name = CoreIdentifier::SelfDestruct}, object_id); diff --git a/toolchain/check/operator.h b/toolchain/check/operator.h index 1c2d64e7e697..4ca7fc34a286 100644 --- a/toolchain/check/operator.h +++ b/toolchain/check/operator.h @@ -49,8 +49,8 @@ auto BuildBinaryOperator( // Builds `.(Destroy.SelfDestruct)()`, converting adapters to their // underlying types in the process. -auto BuildSelfDestructCall(Context& context, SemIR::LocId loc_id, - SemIR::InstId object_id) -> SemIR::InstId; +auto BuildSelfDestructCall(Context& context, SemIR::InstId object_id) + -> SemIR::InstId; } // namespace Carbon::Check diff --git a/toolchain/check/testdata/interop/cpp/function/export/generic.carbon b/toolchain/check/testdata/interop/cpp/function/export/generic.carbon index deb279179f86..1ff2a4421839 100644 --- a/toolchain/check/testdata/interop/cpp/function/export/generic.carbon +++ b/toolchain/check/testdata/interop/cpp/function/export/generic.carbon @@ -212,7 +212,6 @@ void CallUnsupportedF() { // CHECK:STDOUT: %specific_impl_fn.275: = specific_impl_function %impl.elem0.2e5, @I.WithSelf.Doit(%T) [symbolic] // CHECK:STDOUT: %self.param_patt.039: %pattern_type.e39 = ref_param_pattern [concrete] // CHECK:STDOUT: %self.patt.535: %pattern_type.e39 = wrapper_binding_pattern self, %self.param_patt.039 [concrete] -// CHECK:STDOUT: %Destroy.type: type = facet_type <@Destroy> [concrete] // CHECK:STDOUT: %pattern_type.a96: type = pattern_type %empty_struct_type [concrete] // CHECK:STDOUT: %self.param_patt.52f: %pattern_type.a96 = ref_param_pattern [concrete] // CHECK:STDOUT: %self.patt.4b1: %pattern_type.a96 = wrapper_binding_pattern self, %self.param_patt.52f [concrete] @@ -226,10 +225,6 @@ void CallUnsupportedF() { // CHECK:STDOUT: %Destroy.WithSelf.Op.403171.2: %Destroy.WithSelf.Op.type.ef016f.2 = struct_value () [concrete] // CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.type.fbceb5.2: type = fn_type @Destroy.WithSelf.SelfDestruct.loc16_9.2 [concrete] // CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.db3fdb.2: %Destroy.WithSelf.SelfDestruct.type.fbceb5.2 = struct_value () [concrete] -// CHECK:STDOUT: %custom_witness.f8f19d.2: = custom_witness (%Destroy.WithSelf.Op.403171.2, %Destroy.WithSelf.SubobjectDestroy.d01daf.2, %Destroy.WithSelf.SelfDestruct.db3fdb.2), @Destroy [concrete] -// CHECK:STDOUT: %Destroy.facet.872: %Destroy.type = facet_value %B, (%custom_witness.f8f19d.2) [concrete] -// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.type.0b2: type = fn_type @Destroy.WithSelf.SelfDestruct.1, @Destroy.WithSelf(%Destroy.facet.872) [concrete] -// CHECK:STDOUT: %.0fa: type = fn_type_with_self_type %Destroy.WithSelf.SelfDestruct.type.0b2, %Destroy.facet.872 [concrete] // CHECK:STDOUT: %self.param_patt.8fb: %pattern_type.9ef = ref_param_pattern [concrete] // CHECK:STDOUT: %self.patt.e64: %pattern_type.9ef = wrapper_binding_pattern self, %self.param_patt.8fb [concrete] // CHECK:STDOUT: %Destroy.WithSelf.SubobjectDestroy.type.dfcbdb.3: type = fn_type @Destroy.WithSelf.SubobjectDestroy.loc9 [concrete] @@ -238,10 +233,6 @@ void CallUnsupportedF() { // CHECK:STDOUT: %Destroy.WithSelf.Op.403171.3: %Destroy.WithSelf.Op.type.ef016f.3 = struct_value () [concrete] // CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.type.fbceb5.3: type = fn_type @Destroy.WithSelf.SelfDestruct.loc9 [concrete] // CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.db3fdb.3: %Destroy.WithSelf.SelfDestruct.type.fbceb5.3 = struct_value () [concrete] -// CHECK:STDOUT: %custom_witness.f8f19d.3: = custom_witness (%Destroy.WithSelf.Op.403171.3, %Destroy.WithSelf.SubobjectDestroy.d01daf.3, %Destroy.WithSelf.SelfDestruct.db3fdb.3), @Destroy [concrete] -// CHECK:STDOUT: %Destroy.facet.61a: %Destroy.type = facet_value %A, (%custom_witness.f8f19d.3) [concrete] -// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.type.fb1: type = fn_type @Destroy.WithSelf.SelfDestruct.1, @Destroy.WithSelf(%Destroy.facet.61a) [concrete] -// CHECK:STDOUT: %.353: type = fn_type_with_self_type %Destroy.WithSelf.SelfDestruct.type.fb1, %Destroy.facet.61a [concrete] // CHECK:STDOUT: %t.param_patt.169: %pattern_type.9ef = value_param_pattern [concrete] // CHECK:STDOUT: %t.patt.490: %pattern_type.9ef = wrapper_binding_pattern t, %t.param_patt.169 [concrete] // CHECK:STDOUT: %F.specific_fn.9d8: = specific_function %F, @F(%I.facet.f31) [concrete] @@ -520,9 +511,8 @@ void CallUnsupportedF() { // CHECK:STDOUT: // CHECK:STDOUT: fn @B.__destroy_thunk(%self.param: ref %B) { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %impl.elem2: %.0fa = impl_witness_access constants.%custom_witness.f8f19d.2, element2 [concrete = constants.%Destroy.WithSelf.SelfDestruct.db3fdb.2] -// CHECK:STDOUT: %bound_method: = bound_method %self.param, %impl.elem2 -// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.call: init %empty_tuple.type = call %bound_method(%self.param) +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.bound: = bound_method %self.param, constants.%Destroy.WithSelf.SelfDestruct.db3fdb.2 +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.call: init %empty_tuple.type = call %Destroy.WithSelf.SelfDestruct.bound(%self.param) // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -553,9 +543,8 @@ void CallUnsupportedF() { // CHECK:STDOUT: // CHECK:STDOUT: fn @A.__destroy_thunk(%self.param: ref %A) { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %impl.elem2: %.353 = impl_witness_access constants.%custom_witness.f8f19d.3, element2 [concrete = constants.%Destroy.WithSelf.SelfDestruct.db3fdb.3] -// CHECK:STDOUT: %bound_method: = bound_method %self.param, %impl.elem2 -// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.call: init %empty_tuple.type = call %bound_method(%self.param) +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.bound: = bound_method %self.param, constants.%Destroy.WithSelf.SelfDestruct.db3fdb.3 +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.call: init %empty_tuple.type = call %Destroy.WithSelf.SelfDestruct.bound(%self.param) // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/thunk.cpp b/toolchain/check/thunk.cpp index 8040561d2d92..c8b9942c04ba 100644 --- a/toolchain/check/thunk.cpp +++ b/toolchain/check/thunk.cpp @@ -554,7 +554,7 @@ auto BuildDestroyThunk(Context& context, SemIR::LocId loc_id, auto self_inst_id = params[0]; // Build the function body. This calls the `Destroy` operator on `self`. - auto destroy_inst_id = BuildSelfDestructCall(context, loc_id, self_inst_id); + auto destroy_inst_id = BuildSelfDestructCall(context, self_inst_id); DiscardExpr(context, destroy_inst_id); BuildReturnWithNoExpr(context, loc_id);