Canonicalize generated functions for Core witnesses (#7729)

Use a single `SemIR::Function` per `Core` interface method, whether it's
generated locally or imported. This prevents generating duplicate
functions, which lead to different types when the witness appears in a
`FacetValue` as part of a specific for a class.

We use a `CanonicalValueStore` of `GeneratedFunction` objects that allow
finding an existing FunctionId for a `Generated` special function before
(re-)generating it. Mangling for `Generated` functions is also moved to
use the values from the `GeneratedFunction`'s canonicalization key, so
that we have a consistent source of truth for the unique ID of a
`Generated` function across all files.

New tests are in
`toolchain/check/testdata/impl/custom_witness/destroy.carbon`.
This commit is contained in:
Dana Jansens
2026-09-15 16:02:13 +00:00
committed by GitHub
parent db2e26ba86
commit 4416f3525b
278 changed files with 5941 additions and 5506 deletions
+28 -28
View File
@@ -71,13 +71,13 @@ fn M() {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: nounwind
// CHECK:STDOUT: define weak_odr void @"_COp.cbd14a388b4a1c25:core.Destroy.Core"(ptr %self) #0 !dbg !51 {
// CHECK:STDOUT: define weak_odr void @"_COp.08d9e38b928ba575:core.Destroy.Core"(ptr %self) #0 !dbg !51 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: ret void, !dbg !53
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: nounwind
// CHECK:STDOUT: define weak_odr void @"_COp.a1ae3d31ab69a7f8:core.Destroy.Core"(ptr %self) #0 !dbg !55 {
// CHECK:STDOUT: define weak_odr void @"_COp.dc14d4dd21801791:core.Destroy.Core"(ptr %self) #0 !dbg !55 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: ret void, !dbg !57
// CHECK:STDOUT: }
@@ -94,18 +94,18 @@ fn M() {
// CHECK:STDOUT: %.loc52 = load i32, ptr %n.var, align 4, !dbg !64
// CHECK:STDOUT: call void @_CF.Main.84588f41d61dafba(i32 %.loc52), !dbg !65
// CHECK:STDOUT: %.loc53_18 = load i32, ptr %n.var, align 4, !dbg !66
// CHECK:STDOUT: %G.call.loc53 = call i32 @_CG.Main.553a1f59d1dd8381(i32 %.loc53_18), !dbg !67
// CHECK:STDOUT: %G.call.loc53 = call i32 @_CG.Main.89a3e87df6fdafe1(i32 %.loc53_18), !dbg !67
// CHECK:STDOUT: %.loc54 = load double, ptr %p.var, align 8, !dbg !72
// CHECK:STDOUT: call void @_CF.Main.073fbce68be6103e(double %.loc54), !dbg !73
// CHECK:STDOUT: %.loc55_18 = load double, ptr %p.var, align 8, !dbg !74
// CHECK:STDOUT: %G.call.loc55 = call double @_CG.Main.2c62211f0854a75a(double %.loc55_18), !dbg !75
// CHECK:STDOUT: call void @"_COp.a1ae3d31ab69a7f8:core.Destroy.Core"(ptr %p.var), !dbg !62
// CHECK:STDOUT: call void @"_COp.70db2d92ffddbef7:core.Destroy.Core"(ptr %n.var), !dbg !60
// CHECK:STDOUT: %G.call.loc55 = call double @_CG.Main.38241ddc2cd9d74d(double %.loc55_18), !dbg !75
// CHECK:STDOUT: call void @"_COp.dc14d4dd21801791:core.Destroy.Core"(ptr %p.var), !dbg !62
// CHECK:STDOUT: call void @"_COp.f58524831c37807e:core.Destroy.Core"(ptr %n.var), !dbg !60
// CHECK:STDOUT: ret void, !dbg !78
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: nounwind
// CHECK:STDOUT: define weak_odr void @"_COp.70db2d92ffddbef7:core.Destroy.Core"(ptr %self) #0 !dbg !79 {
// CHECK:STDOUT: define weak_odr void @"_COp.f58524831c37807e:core.Destroy.Core"(ptr %self) #0 !dbg !79 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: ret void, !dbg !81
// CHECK:STDOUT: }
@@ -123,7 +123,7 @@ fn M() {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: nounwind
// CHECK:STDOUT: define linkonce_odr i32 @_CG.Main.553a1f59d1dd8381(i32 %x) #0 !dbg !88 {
// CHECK:STDOUT: define linkonce_odr i32 @_CG.Main.89a3e87df6fdafe1(i32 %x) #0 !dbg !88 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %.loc29_6.3.temp = alloca i32, align 4, !dbg !94
// CHECK:STDOUT: %.loc31_8.3.temp = alloca i32, align 4, !dbg !97
@@ -137,17 +137,17 @@ fn M() {
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc29_6.3.temp), !dbg !94
// CHECK:STDOUT: %H.call.loc29 = call i32 @_CH.Main.4d6ceefeb7f772f4(i32 %x), !dbg !94
// CHECK:STDOUT: store i32 %H.call.loc29, ptr %.loc29_6.3.temp, align 4, !dbg !94
// CHECK:STDOUT: call void @"_COp.70db2d92ffddbef7:core.Destroy.Core"(ptr %.loc29_6.3.temp), !dbg !94
// CHECK:STDOUT: call void @"_COp.f58524831c37807e:core.Destroy.Core"(ptr %.loc29_6.3.temp), !dbg !94
// CHECK:STDOUT: %H.call.loc30 = call %type.26 @_CH.Main.71d6c598da8ca542(%type.26 zeroinitializer), !dbg !95
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc31_8.3.temp), !dbg !97
// CHECK:STDOUT: %G.call = call i32 @_CG.Main.553a1f59d1dd8381(i32 %x), !dbg !97
// CHECK:STDOUT: %G.call = call i32 @_CG.Main.89a3e87df6fdafe1(i32 %x), !dbg !97
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc31_9.3.temp), !dbg !98
// CHECK:STDOUT: store i32 %G.call, ptr %.loc31_8.3.temp, align 4, !dbg !97
// CHECK:STDOUT: %.loc31_8.5 = load i32, ptr %.loc31_8.3.temp, align 4, !dbg !97
// CHECK:STDOUT: %H.call.loc31 = call i32 @_CH.Main.4d6ceefeb7f772f4(i32 %.loc31_8.5), !dbg !98
// CHECK:STDOUT: store i32 %H.call.loc31, ptr %.loc31_9.3.temp, align 4, !dbg !98
// CHECK:STDOUT: call void @"_COp.70db2d92ffddbef7:core.Destroy.Core"(ptr %.loc31_9.3.temp), !dbg !98
// CHECK:STDOUT: call void @"_COp.70db2d92ffddbef7:core.Destroy.Core"(ptr %.loc31_8.3.temp), !dbg !97
// CHECK:STDOUT: call void @"_COp.f58524831c37807e:core.Destroy.Core"(ptr %.loc31_9.3.temp), !dbg !98
// CHECK:STDOUT: call void @"_COp.f58524831c37807e:core.Destroy.Core"(ptr %.loc31_8.3.temp), !dbg !97
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %var_f64.var), !dbg !99
// CHECK:STDOUT: store double poison, ptr %var_f64.var, align 8, !dbg !99
// CHECK:STDOUT: %.loc35_5 = load double, ptr %var_f64.var, align 8, !dbg !101
@@ -167,9 +167,9 @@ fn M() {
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %c.var), !dbg !115
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc43_6.3.temp), !dbg !118
// CHECK:STDOUT: call void @_CH.Main.42513763e01cba2c(ptr %.loc43_6.3.temp, ptr %c.var), !dbg !118
// CHECK:STDOUT: call void @"_COp.cbd14a388b4a1c25:core.Destroy.Core"(ptr %.loc43_6.3.temp), !dbg !118
// CHECK:STDOUT: call void @"_COp.cbd14a388b4a1c25:core.Destroy.Core"(ptr %c.var), !dbg !115
// CHECK:STDOUT: call void @"_COp.a1ae3d31ab69a7f8:core.Destroy.Core"(ptr %var_f64.var), !dbg !99
// CHECK:STDOUT: call void @"_COp.08d9e38b928ba575:core.Destroy.Core"(ptr %.loc43_6.3.temp), !dbg !118
// CHECK:STDOUT: call void @"_COp.08d9e38b928ba575:core.Destroy.Core"(ptr %c.var), !dbg !115
// CHECK:STDOUT: call void @"_COp.dc14d4dd21801791:core.Destroy.Core"(ptr %var_f64.var), !dbg !99
// CHECK:STDOUT: ret i32 %x, !dbg !120
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -180,7 +180,7 @@ fn M() {
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: nounwind
// CHECK:STDOUT: define linkonce_odr double @_CG.Main.2c62211f0854a75a(double %x) #0 !dbg !127 {
// CHECK:STDOUT: define linkonce_odr double @_CG.Main.38241ddc2cd9d74d(double %x) #0 !dbg !127 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %.loc29_6.3.temp = alloca double, align 8, !dbg !133
// CHECK:STDOUT: %.loc31_8.3.temp = alloca double, align 8, !dbg !136
@@ -194,17 +194,17 @@ fn M() {
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc29_6.3.temp), !dbg !133
// CHECK:STDOUT: %H.call.loc29 = call double @_CH.Main.c5e4ba542a56b71f(double %x), !dbg !133
// CHECK:STDOUT: store double %H.call.loc29, ptr %.loc29_6.3.temp, align 8, !dbg !133
// CHECK:STDOUT: call void @"_COp.a1ae3d31ab69a7f8:core.Destroy.Core"(ptr %.loc29_6.3.temp), !dbg !133
// CHECK:STDOUT: call void @"_COp.dc14d4dd21801791:core.Destroy.Core"(ptr %.loc29_6.3.temp), !dbg !133
// CHECK:STDOUT: %H.call.loc30 = call %type.26 @_CH.Main.71d6c598da8ca542(%type.26 zeroinitializer), !dbg !134
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc31_8.3.temp), !dbg !136
// CHECK:STDOUT: %G.call = call double @_CG.Main.2c62211f0854a75a(double %x), !dbg !136
// CHECK:STDOUT: %G.call = call double @_CG.Main.38241ddc2cd9d74d(double %x), !dbg !136
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc31_9.3.temp), !dbg !137
// CHECK:STDOUT: store double %G.call, ptr %.loc31_8.3.temp, align 8, !dbg !136
// CHECK:STDOUT: %.loc31_8.5 = load double, ptr %.loc31_8.3.temp, align 8, !dbg !136
// CHECK:STDOUT: %H.call.loc31 = call double @_CH.Main.c5e4ba542a56b71f(double %.loc31_8.5), !dbg !137
// CHECK:STDOUT: store double %H.call.loc31, ptr %.loc31_9.3.temp, align 8, !dbg !137
// CHECK:STDOUT: call void @"_COp.a1ae3d31ab69a7f8:core.Destroy.Core"(ptr %.loc31_9.3.temp), !dbg !137
// CHECK:STDOUT: call void @"_COp.a1ae3d31ab69a7f8:core.Destroy.Core"(ptr %.loc31_8.3.temp), !dbg !136
// CHECK:STDOUT: call void @"_COp.dc14d4dd21801791:core.Destroy.Core"(ptr %.loc31_9.3.temp), !dbg !137
// CHECK:STDOUT: call void @"_COp.dc14d4dd21801791:core.Destroy.Core"(ptr %.loc31_8.3.temp), !dbg !136
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %var_f64.var), !dbg !138
// CHECK:STDOUT: store double poison, ptr %var_f64.var, align 8, !dbg !138
// CHECK:STDOUT: %.loc35_5 = load double, ptr %var_f64.var, align 8, !dbg !140
@@ -224,9 +224,9 @@ fn M() {
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %c.var), !dbg !154
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc43_6.3.temp), !dbg !157
// CHECK:STDOUT: call void @_CH.Main.42513763e01cba2c(ptr %.loc43_6.3.temp, ptr %c.var), !dbg !157
// CHECK:STDOUT: call void @"_COp.cbd14a388b4a1c25:core.Destroy.Core"(ptr %.loc43_6.3.temp), !dbg !157
// CHECK:STDOUT: call void @"_COp.cbd14a388b4a1c25:core.Destroy.Core"(ptr %c.var), !dbg !154
// CHECK:STDOUT: call void @"_COp.a1ae3d31ab69a7f8:core.Destroy.Core"(ptr %var_f64.var), !dbg !138
// CHECK:STDOUT: call void @"_COp.08d9e38b928ba575:core.Destroy.Core"(ptr %.loc43_6.3.temp), !dbg !157
// CHECK:STDOUT: call void @"_COp.08d9e38b928ba575:core.Destroy.Core"(ptr %c.var), !dbg !154
// CHECK:STDOUT: call void @"_COp.dc14d4dd21801791:core.Destroy.Core"(ptr %var_f64.var), !dbg !138
// CHECK:STDOUT: ret double %x, !dbg !159
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -293,11 +293,11 @@ fn M() {
// CHECK:STDOUT: !45 = !DILocalVariable(arg: 1, scope: !44, type: !35)
// CHECK:STDOUT: !49 = !DILocation(line: 15, column: 34, scope: !44)
// CHECK:STDOUT: !50 = !{!45}
// CHECK:STDOUT: !51 = distinct !DISubprogram(name: "Op", linkageName: "_COp.cbd14a388b4a1c25:core.Destroy.Core", scope: null, file: !32, line: 43, type: !39, spFlags: DISPFlagDefinition, unit: !33, retainedNodes: !54)
// CHECK:STDOUT: !51 = distinct !DISubprogram(name: "Op", linkageName: "_COp.08d9e38b928ba575:core.Destroy.Core", scope: null, file: !32, line: 43, type: !39, spFlags: DISPFlagDefinition, unit: !33, retainedNodes: !54)
// CHECK:STDOUT: !52 = !DILocalVariable(arg: 1, scope: !51, type: !35)
// CHECK:STDOUT: !53 = !DILocation(line: 43, column: 3, scope: !51)
// CHECK:STDOUT: !54 = !{!52}
// CHECK:STDOUT: !55 = distinct !DISubprogram(name: "Op", linkageName: "_COp.a1ae3d31ab69a7f8:core.Destroy.Core", scope: null, file: !32, line: 34, type: !39, spFlags: DISPFlagDefinition, unit: !33, retainedNodes: !58)
// CHECK:STDOUT: !55 = distinct !DISubprogram(name: "Op", linkageName: "_COp.dc14d4dd21801791:core.Destroy.Core", scope: null, file: !32, line: 34, type: !39, spFlags: DISPFlagDefinition, unit: !33, retainedNodes: !58)
// CHECK:STDOUT: !56 = !DILocalVariable(arg: 1, scope: !55, type: !35)
// CHECK:STDOUT: !57 = !DILocation(line: 34, column: 3, scope: !55)
// CHECK:STDOUT: !58 = !{!56}
@@ -315,7 +315,7 @@ fn M() {
// CHECK:STDOUT: !74 = !DILocation(line: 55, column: 18, scope: !59)
// CHECK:STDOUT: !75 = !DILocation(line: 55, column: 16, scope: !59)
// CHECK:STDOUT: !78 = !DILocation(line: 48, column: 1, scope: !59)
// CHECK:STDOUT: !79 = distinct !DISubprogram(name: "Op", linkageName: "_COp.70db2d92ffddbef7:core.Destroy.Core", scope: null, file: !32, line: 53, type: !43, spFlags: DISPFlagDefinition, unit: !33, retainedNodes: !82)
// CHECK:STDOUT: !79 = distinct !DISubprogram(name: "Op", linkageName: "_COp.f58524831c37807e:core.Destroy.Core", scope: null, file: !32, line: 53, type: !43, spFlags: DISPFlagDefinition, unit: !33, retainedNodes: !82)
// CHECK:STDOUT: !80 = !DILocalVariable(arg: 1, scope: !79, type: !34)
// CHECK:STDOUT: !81 = !DILocation(line: 53, column: 16, scope: !79)
// CHECK:STDOUT: !82 = !{!80}
@@ -323,7 +323,7 @@ fn M() {
// CHECK:STDOUT: !84 = !DILocalVariable(arg: 1, scope: !83, type: !34)
// CHECK:STDOUT: !86 = !DILocation(line: 19, column: 1, scope: !83)
// CHECK:STDOUT: !87 = !{!84}
// CHECK:STDOUT: !88 = distinct !DISubprogram(name: "G", linkageName: "_CG.Main.553a1f59d1dd8381", scope: null, file: !32, line: 28, type: !69, spFlags: DISPFlagDefinition, unit: !33, retainedNodes: !121)
// CHECK:STDOUT: !88 = distinct !DISubprogram(name: "G", linkageName: "_CG.Main.89a3e87df6fdafe1", scope: null, file: !32, line: 28, type: !69, spFlags: DISPFlagDefinition, unit: !33, retainedNodes: !121)
// CHECK:STDOUT: !89 = !DILocalVariable(arg: 1, scope: !88, type: !34)
// CHECK:STDOUT: !94 = !DILocation(line: 29, column: 3, scope: !88)
// CHECK:STDOUT: !95 = !DILocation(line: 30, column: 3, scope: !88)
@@ -349,7 +349,7 @@ fn M() {
// CHECK:STDOUT: !123 = !DILocalVariable(arg: 1, scope: !122, type: !35)
// CHECK:STDOUT: !125 = !DILocation(line: 19, column: 1, scope: !122)
// CHECK:STDOUT: !126 = !{!123}
// CHECK:STDOUT: !127 = distinct !DISubprogram(name: "G", linkageName: "_CG.Main.2c62211f0854a75a", scope: null, file: !32, line: 28, type: !37, spFlags: DISPFlagDefinition, unit: !33, retainedNodes: !160)
// CHECK:STDOUT: !127 = distinct !DISubprogram(name: "G", linkageName: "_CG.Main.38241ddc2cd9d74d", scope: null, file: !32, line: 28, type: !37, spFlags: DISPFlagDefinition, unit: !33, retainedNodes: !160)
// CHECK:STDOUT: !128 = !DILocalVariable(arg: 1, scope: !127, type: !35)
// CHECK:STDOUT: !133 = !DILocation(line: 29, column: 3, scope: !127)
// CHECK:STDOUT: !134 = !DILocation(line: 30, column: 3, scope: !127)