Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Serialization] Handle XREFs to private types
We can encounter these when the compiler modifies an inlinable function to break apart a struct and the struct uses a private type for one of its fields. It's questionable whether we /should/ handle this, but meanwhile this /is/ a non-intrusive fix that preserves the performance of non-resilient libraries. (That is, it appears this worked in Swift 4.0, though perhaps not all of the same optimizations kicked in.) https://bugs.swift.org/browse/SR-6874
- Loading branch information
1 parent
d9067d9
commit b9d3c6e
Showing
7 changed files
with
156 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import LibCore | ||
|
||
public let lazyFoo = Foo() | ||
public func testFoo(_: Foo = lazyFoo) {} | ||
public let lazyBar = Bar() | ||
public func testBar(_: Bar = lazyBar) {} | ||
public let lazyBaz = Baz() | ||
public func testBaz(_: Baz = lazyBaz) {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
private class TopLevelInternalClass {} | ||
public struct Foo { | ||
private var ref: TopLevelInternalClass | ||
|
||
public init() { self.ref = .init() } | ||
} | ||
|
||
public struct Bar { | ||
private class NestedInternalClass {} | ||
|
||
private var ref: NestedInternalClass | ||
|
||
public init() { self.ref = .init() } | ||
} | ||
|
||
public struct Baz { | ||
fileprivate class NestedInternalClass { | ||
fileprivate class DoublyNestedInternalClass {} | ||
} | ||
|
||
private var ref: NestedInternalClass.DoublyNestedInternalClass | ||
|
||
public init() { self.ref = .init() } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// RUN: %empty-directory(%t) | ||
// RUN: %target-build-swift -swift-version 4 -O -force-single-frontend-invocation -emit-module-path %t/LibCore.swiftmodule %S/Inputs/xref-private-type/LibCore.swift | ||
// RUN: %target-build-swift -swift-version 4 -O -I %t -force-single-frontend-invocation -emit-module-path %t/Lib.swiftmodule %S/Inputs/xref-private-type/Lib.swift | ||
// RUN: %target-build-swift -swift-version 4 -O -I %t -emit-sil %s | %FileCheck %s | ||
|
||
import Lib | ||
|
||
// CHECK: sil{{.*}} @[[TESTSR6874:[^ ]+10testSR6874[^ ]+]] : | ||
func testSR6874() { | ||
// The important lines in this test are the strong_retains, which refer to | ||
// private types defined in LibCore. Normally we shouldn't have references to | ||
// non-public declarations in inlinable code, but because SIL passes can break | ||
// apart non-resilient structs and enums we can end up in that situation. | ||
// Worse, this can happen *across module boundaries.* | ||
// | ||
// In this test, the addressor for each global defined in Lib ends up | ||
// referencing private types defined in LibCore. Using those globals in | ||
// default argument position leads to the addressor getting inlined into | ||
// calling code in Swift 4 and later. This results in an attempt to not just | ||
// reference a private type, but to *resolve a cross-reference to a private | ||
// type.* | ||
// | ||
// This is the situation in SR-6874 (simplified). I'm not sure of a simpler | ||
// way to reliably trigger the issue. But if this test breaks, please try to | ||
// find one. | ||
// | ||
// (We may want to revisit this whole thing later, as it violates the model. | ||
// But it's also useful for performance in non-resilient code.) | ||
|
||
// CHECK: [[ADDR:%.+]] = global_addr @{{[^ ]+}}3Lib7lazyFoo | ||
// CHECK: [[LOADED:%.+]] = load [[ADDR]] : $*Foo | ||
// CHECK: [[REF:%.+]] = struct_extract [[LOADED]] : $Foo, #Foo.ref | ||
// CHECK: strong_retain [[REF]] : $TopLevelInternalClass | ||
// CHECK: apply {{%.+}}([[LOADED]]) | ||
testFoo() | ||
|
||
// CHECK: [[ADDR:%.+]] = global_addr @{{[^ ]+}}3Lib7lazyBar | ||
// CHECK: [[LOADED:%.+]] = load [[ADDR]] : $*Bar | ||
// CHECK: [[REF:%.+]] = struct_extract [[LOADED]] : $Bar, #Bar.ref | ||
// CHECK: strong_retain [[REF]] : $Bar.NestedInternalClass | ||
// CHECK: apply {{%.+}}([[LOADED]]) | ||
testBar() | ||
|
||
// CHECK: [[ADDR:%.+]] = global_addr @{{[^ ]+}}3Lib7lazyBaz | ||
// CHECK: [[LOADED:%.+]] = load [[ADDR]] : $*Baz | ||
// CHECK: [[REF:%.+]] = struct_extract [[LOADED]] : $Baz, #Baz.ref | ||
// CHECK: strong_retain [[REF]] : $Baz.NestedInternalClass.DoublyNestedInternalClass | ||
// CHECK: apply {{%.+}}([[LOADED]]) | ||
testBaz() | ||
} // CHECK: end sil function '[[TESTSR6874]]' | ||
|