Skip to content

Commit b5e731d

Browse files
committed
WalkUtils: fix a crash when visiting mismatching types
The path components may not be related to the current value in case mismatching types are visited, e.g. different concrete types of an existential. This can lead to mismatching operand numbers for struct and tuple instructions. rdar://104435056
1 parent 9618083 commit b5e731d

File tree

2 files changed

+45
-1
lines changed

2 files changed

+45
-1
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/WalkUtils.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,11 @@ extension ValueUseDefWalker {
569569
switch def {
570570
case let str as StructInst:
571571
if let (index, path) = path.pop(kind: .structField) {
572+
if index >= str.operands.count {
573+
// This can happen if there is a type mismatch, e.g. two different concrete types of an existential
574+
// are visited for the same path.
575+
return unmatchedPath(value: str, path: path)
576+
}
572577
return walkUp(value: str.operands[index].value, path: path)
573578
} else if path.popIfMatches(.anyValueFields, index: nil) != nil {
574579
return walkUpAllOperands(of: str, path: path)
@@ -577,6 +582,11 @@ extension ValueUseDefWalker {
577582
}
578583
case let t as TupleInst:
579584
if let (index, path) = path.pop(kind: .tupleField) {
585+
if index >= t.operands.count {
586+
// This can happen if there is a type mismatch, e.g. two different concrete types of an existential
587+
// are visited for the same path.
588+
return unmatchedPath(value: t, path: path)
589+
}
580590
return walkUp(value: t.operands[index].value, path: path)
581591
} else if path.popIfMatches(.anyValueFields, index: nil) != nil {
582592
return walkUpAllOperands(of: t, path: path)

test/SILOptimizer/escape_info.sil

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,14 @@ final class F {
4141
@_hasStorage var y: Y
4242
}
4343

44-
struct TwoF {
44+
protocol P {
45+
}
46+
47+
struct OneF : P {
48+
@_hasStorage var a: F
49+
}
50+
51+
struct TwoF : P {
4552
@_hasStorage var a: F
4653
@_hasStorage var b: F
4754
}
@@ -1343,3 +1350,30 @@ bb0:
13431350
return %13 : $()
13441351
}
13451352

1353+
// CHECK-LABEL: Escape information for test_mismatching_existential_types:
1354+
// CHECK: - : %1 = alloc_ref $Y
1355+
// CHECK: End function test_mismatching_existential_types
1356+
sil @test_mismatching_existential_types : $@convention(thin) (@guaranteed F) -> () {
1357+
bb0(%0 : $F):
1358+
%1 = alloc_ref $Y
1359+
1360+
%2 = alloc_stack $any P
1361+
1362+
%3 = init_existential_addr %2 : $*any P, $OneF
1363+
%4 = struct $OneF (%0 : $F)
1364+
store %4 to %3 : $*OneF
1365+
1366+
// Strictly speaking it's illegal to re-initialize an existential with a different concrete type.
1367+
// But for this test this doesn't matter.
1368+
%6 = init_existential_addr %2 : $*any P, $TwoF
1369+
%7 = struct_element_addr %6 : $*TwoF, #TwoF.b
1370+
%8 = load %7 : $*F
1371+
1372+
%9 = ref_element_addr %8 : $F, #F.y
1373+
store %1 to %9 : $*Y
1374+
1375+
dealloc_stack %2 : $*any P
1376+
%r = tuple()
1377+
return %r : $()
1378+
}
1379+

0 commit comments

Comments
 (0)