Change the Destroy blanket impls to be more specific (#6098)

The main direction of this change is the edits to `destroy.carbon`
(matching in both prelude and min_prelude).

Previously there was a no-op blanket impl for `Destroy`, which hid all
missing implementations of `Destroy`. This does a few things:

- Sets up builtin aggregate destruction for struct and tuple types as
before, but also adds C++ class types and array types to the same
handling. (all as a TODO for actual implementation)
- Also maybe-unformed destruction, for now at least. (there's a chance I
may try a different approach on this, but the impl lookup wasn't working
as I'd hope in order to write it in code)
- Adds handlers for simple things that are easy to do in code: `type`,
`bool`, pointers. (because these are no-op destruction)
- Redirect `const T` destruction to `T` destruction.

This leaves as future issues:

- `partial T` destruction. (this can't be done similar to `const`
because it only works for non-`final` class types; I think `class`
definitions should just generate what's needed)
- Destruction of other prelude-provided types. (will probably come up as
we implement class destruction, that the adapted builtin type doesn't
implement `Destroy` -- but may end up special-casing that in a way that
moots it)

This moves the `&` operator from `facet_types.carbon` to
`convert.carbon` because more things need to handle type and now that
we're getting separate copy and destroy interfaces. It should be
low-cost (an interface and builtin) so hopefully this is the right
balance for complexity and re-use.

A few tests are also edited in order to focus them more on what they
intend to test, and avoid a `Destroy` dependency.
This commit is contained in:
Jon Ross-Perkins
2025-09-18 22:10:50 +00:00
committed by GitHub
parent 868c4b768c
commit 9704dc670e
143 changed files with 3271 additions and 2413 deletions
@@ -21,7 +21,7 @@ fn H[T:! Core.Copy](x: T) -> T {
return x;
}
fn G[T:! Core.Copy](x: T) -> T {
fn G[T:! Core.Copy & Core.Destroy](x: T) -> T {
H(x);
F(x);
return x;
@@ -48,7 +48,7 @@ fn M() {
// CHECK:STDOUT: %.loc34 = load i32, ptr %n.var, align 4, !dbg !9
// CHECK:STDOUT: call void @_CF.Main.b88d1103f417c6d4(i32 %.loc34), !dbg !10
// CHECK:STDOUT: %.loc35_9 = load i32, ptr %n.var, align 4, !dbg !11
// CHECK:STDOUT: %G.call = call i32 @_CG.Main.de631560529e9861(i32 %.loc35_9), !dbg !12
// CHECK:STDOUT: %G.call = call i32 @_CG.Main.dedae426f8f6526d(i32 %.loc35_9), !dbg !12
// CHECK:STDOUT: store i32 %G.call, ptr %m.var, align 4, !dbg !13
// CHECK:STDOUT: ret void, !dbg !14
// CHECK:STDOUT: }
@@ -61,7 +61,7 @@ fn M() {
// CHECK:STDOUT: ret void, !dbg !16
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define linkonce_odr i32 @_CG.Main.de631560529e9861(i32 %x) !dbg !17 {
// CHECK:STDOUT: define linkonce_odr i32 @_CG.Main.dedae426f8f6526d(i32 %x) !dbg !17 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %.loc25_6.3.temp = alloca i32, align 4, !dbg !18
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc25_6.3.temp), !dbg !18
@@ -102,7 +102,7 @@ fn M() {
// CHECK:STDOUT: !14 = !DILocation(line: 30, column: 1, scope: !4)
// CHECK:STDOUT: !15 = distinct !DISubprogram(name: "F", linkageName: "_CF.Main.b88d1103f417c6d4", scope: null, file: !3, line: 16, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !16 = !DILocation(line: 16, column: 1, scope: !15)
// CHECK:STDOUT: !17 = distinct !DISubprogram(name: "G", linkageName: "_CG.Main.de631560529e9861", scope: null, file: !3, line: 24, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !17 = distinct !DISubprogram(name: "G", linkageName: "_CG.Main.dedae426f8f6526d", scope: null, file: !3, line: 24, type: !5, spFlags: DISPFlagDefinition, unit: !2)
// CHECK:STDOUT: !18 = !DILocation(line: 25, column: 3, scope: !17)
// CHECK:STDOUT: !19 = !DILocation(line: 26, column: 3, scope: !17)
// CHECK:STDOUT: !20 = !DILocation(line: 27, column: 3, scope: !17)