mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
A lazy property setter stores a value to the underlying storage of the lazy property. The underlying storage is private, and it is not proper for a public transparent function body to reference a private member. In practice, this only failed if the private member had a non-constant offset, which only occurs with subclasses of @objc classes, and resilient classes. For @objc classes we already had a workaround where no accessors for stored properties are ever transparent. I put this in to fix this very issue with lazy properties, but now I realize it was the wrong workaround, because we still had this problem with resilient classes. Note that I'm keeping the logic which made @objc accessors non-transparent in place, because there's a good chance we will decide that field offset globals should always be private. Also, to make this issue reproducible in the test, I changed the resilience execution tests to build the resilient library as a dylib and link against that instead of just linking .o files together. This is because .o files can see each other's internal symbols, so I was not able to reproduce the original failure this way. I went ahead and updated the other resilient tests to do this as well. Also, each test now builds in WMO and non-WMO mode, to exercise different SIL linking behavior. Again, the WMO variant was needed to reproduce the issue fixed by this commit, because without WMO we currently discard serialized SIL, so no cross-module inlining of the lazy property setter was taking place.
221 lines
4.6 KiB
Swift
221 lines
4.6 KiB
Swift
|
|
import resilient_struct
|
|
|
|
|
|
// Fixed-layout, fixed-size base class
|
|
|
|
@_fixed_layout
|
|
open class OutsideParent {
|
|
open var property: String = "OutsideParent.property"
|
|
|
|
open class var classProperty: String {
|
|
return "OutsideParent.classProperty"
|
|
}
|
|
|
|
public init() {
|
|
print("OutsideParent.init()")
|
|
}
|
|
|
|
open func method() {
|
|
print("OutsideParent.method()")
|
|
}
|
|
|
|
open class func classMethod() {
|
|
print("OutsideParent.classMethod()")
|
|
}
|
|
}
|
|
|
|
|
|
// Fixed-layout, resiliently-sized base class
|
|
|
|
@_fixed_layout
|
|
open class OutsideParentWithResilientProperty {
|
|
public let p: Point
|
|
public let s: Size
|
|
public let color: Int32
|
|
|
|
public final lazy var laziestNumber = 0
|
|
|
|
public init(p: Point, s: Size, color: Int32) {
|
|
self.p = p
|
|
self.s = s
|
|
self.color = color
|
|
}
|
|
}
|
|
|
|
|
|
// Resilient base class
|
|
|
|
open class ResilientOutsideParent {
|
|
open var property: String = "ResilientOutsideParent.property"
|
|
public final var finalProperty: String = "ResilientOutsideParent.finalProperty"
|
|
|
|
open class var classProperty: String {
|
|
return "ResilientOutsideParent.classProperty"
|
|
}
|
|
|
|
public init() {
|
|
print("ResilientOutsideParent.init()")
|
|
}
|
|
|
|
open func method() {
|
|
print("ResilientOutsideParent.method()")
|
|
}
|
|
|
|
open class func classMethod() {
|
|
print("ResilientOutsideParent.classMethod()")
|
|
}
|
|
}
|
|
|
|
|
|
// Fixed-layout, fixed-size subclass
|
|
|
|
@_fixed_layout
|
|
open class OutsideChild : OutsideParent {
|
|
open override func method() {
|
|
print("OutsideChild.method()")
|
|
super.method()
|
|
}
|
|
|
|
open override class func classMethod() {
|
|
print("OutsideChild.classMethod()")
|
|
super.classMethod()
|
|
}
|
|
}
|
|
|
|
|
|
// Resilient subclass
|
|
|
|
open class ResilientOutsideChild : ResilientOutsideParent {
|
|
open override func method() {
|
|
print("ResilientOutsideChild.method()")
|
|
super.method()
|
|
}
|
|
|
|
open override class func classMethod() {
|
|
print("ResilientOutsideChild.classMethod()")
|
|
super.classMethod()
|
|
}
|
|
}
|
|
|
|
|
|
// Fixed-layout, dependently-sized, generic base class
|
|
|
|
@_fixed_layout
|
|
open class GenericOutsideParent<A> {
|
|
open var property: A
|
|
public init(property: A) {
|
|
self.property = property
|
|
print("GenericOutsideParent.init()")
|
|
}
|
|
|
|
open func method() {
|
|
print("GenericOutsideParent.method()")
|
|
}
|
|
|
|
open class func classMethod() {
|
|
print("GenericOutsideParent.classMethod()")
|
|
}
|
|
}
|
|
|
|
|
|
// Resilient generic base class
|
|
|
|
open class ResilientGenericOutsideParent<A> {
|
|
open var property: A
|
|
public init(property: A) {
|
|
self.property = property
|
|
print("ResilientGenericOutsideParent.init()")
|
|
}
|
|
|
|
open func method() {
|
|
print("ResilientGenericOutsideParent.method()")
|
|
}
|
|
|
|
open class func classMethod() {
|
|
print("ResilientGenericOutsideParent.classMethod()")
|
|
}
|
|
}
|
|
|
|
|
|
// Fixed-layout, dependently-sized, generic subclass
|
|
|
|
@_fixed_layout
|
|
open class GenericOutsideChild<A> : GenericOutsideParent<A> {
|
|
public override init(property: A) {
|
|
print("GenericOutsideGenericChild.init(a: A)")
|
|
super.init(property: property)
|
|
}
|
|
|
|
open override func method() {
|
|
print("GenericOutsideChild.method()")
|
|
super.method()
|
|
}
|
|
|
|
open override class func classMethod() {
|
|
print("GenericOutsideChild.classMethod()")
|
|
super.classMethod()
|
|
}
|
|
}
|
|
|
|
|
|
// Resilient generic subclass
|
|
|
|
open class ResilientGenericOutsideChild<A> : ResilientGenericOutsideParent<A> {
|
|
public override init(property: A) {
|
|
print("ResilientGenericOutsideGenericChild.init(a: A)")
|
|
super.init(property: property)
|
|
}
|
|
|
|
open override func method() {
|
|
print("ResilientGenericOutsideChild.method()")
|
|
super.method()
|
|
}
|
|
|
|
open override class func classMethod() {
|
|
print("ResilientGenericOutsideChild.classMethod()")
|
|
super.classMethod()
|
|
}
|
|
}
|
|
|
|
|
|
// Fixed-layout, fixed-size subclass of generic class
|
|
|
|
@_fixed_layout
|
|
open class ConcreteOutsideChild : GenericOutsideParent<String> {
|
|
public override init(property: String) {
|
|
print("ConcreteOutsideChild.init(property: String)")
|
|
super.init(property: property)
|
|
}
|
|
|
|
open override func method() {
|
|
print("ConcreteOutsideChild.method()")
|
|
super.method()
|
|
}
|
|
|
|
open override class func classMethod() {
|
|
print("ConcreteOutsideChild.classMethod()")
|
|
super.classMethod()
|
|
}
|
|
}
|
|
|
|
|
|
// Resilient subclass of generic class
|
|
|
|
open class ResilientConcreteOutsideChild : ResilientGenericOutsideParent<String> {
|
|
public override init(property: String) {
|
|
print("ResilientConcreteOutsideChild.init(property: String)")
|
|
super.init(property: property)
|
|
}
|
|
|
|
open override func method() {
|
|
print("ResilientConcreteOutsideChild.method()")
|
|
super.method()
|
|
}
|
|
|
|
open override class func classMethod() {
|
|
print("ResilientConcreteOutsideChild.classMethod()")
|
|
super.classMethod()
|
|
}
|
|
}
|