mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This bug is caused by a quirk in the API of the linear lifetime checker. Specifically, even though valueHasLinearLifetime is passed a SILValue (the value whose lifetime one is checking), really it doesnt care about that value (except for error diagnostics). Really it just cares about the parent block of the value since it assumes that the value is guaranteed to dominate all uses. This creates a footgun when if one is writing code using "generic ossa/non-ossa" routines on SILBuilder (the emit*Operation methods), if one in non-ossa code calls that function, it returns the input value of the strong_retain. This causes the linear lifetime error, to use the parent block of the argument of the retain, instead of the parent block of the retain itself. This then causes it to find the wrong leaking blocks and thus insert destroys in the wrong places. I fix this problem in this commit by noting that the partial apply is our original insertion point for the copy, so of course it is going to be in the same block. So I changed the linear lifetime checker to check for leaks with respect to the partial applies result. In a subsequent commit, I am going to add a new API on top of this that is based around the use of the value by the partial apply (maybe extendLifetimeFromUseToInsertionPoint?). By using the use, it will express in code more clearly what is happening here and will insert the copy for you. rdar://54234011
62 lines
1.8 KiB
Swift
62 lines
1.8 KiB
Swift
// RUN: %target-run-simple-swift
|
|
|
|
// REQUIRES: executable_test
|
|
|
|
// This file contains various scenarios that validate that various functional
|
|
// behaviors of mandatory inlining work as expected. Please give each test a
|
|
// descriptive name and a large comment explaining what you are testing.
|
|
|
|
import StdlibUnittest
|
|
|
|
var Tests = TestSuite("MandatoryInlining Functional Tests")
|
|
defer { runAllTests() }
|
|
|
|
func doNotInsertReleaseInLoopIfValueConsumedInLoop(
|
|
callBack: ((String) -> (Void))? = nil) {
|
|
let callBack = callBack ?? { msg in
|
|
print(msg)
|
|
}
|
|
|
|
for _ in 0..<1 {
|
|
callBack("foo bar baz")
|
|
}
|
|
}
|
|
|
|
// When using the linear lifetime checker to insert compensating releases, if we
|
|
// find a double consume due to a loop, do not insert an apply at that call site
|
|
// that is in the loop. There is already a compensating retain in the loop that
|
|
// we are ignoring. This test functionally makes sure we no longer do this.
|
|
Tests.test("doNotInsertReleaseInLoopIfValueConsumedInLoop") {
|
|
doNotInsertReleaseInLoopIfValueConsumedInLoop { msg in
|
|
print(msg)
|
|
}
|
|
}
|
|
|
|
|
|
@propertyWrapper
|
|
public struct Published<Value> {
|
|
public var wrappedValue: Value
|
|
public init(initialValue value: Value) { wrappedValue = value }
|
|
}
|
|
|
|
private class Model {
|
|
var selectedContact: Int? {
|
|
get { _selectedContact }
|
|
set {
|
|
if let contact = newValue {
|
|
self._selectedContact = contact
|
|
}
|
|
}
|
|
}
|
|
|
|
@Published private var _selectedContact: Int? = nil
|
|
}
|
|
|
|
Tests.test("testNonOSSAPartialApplyLifetimeExtension") {
|
|
// If we mess this up, when we set model.selectedContact to nil, we release
|
|
// self incorrectly due to mandatory inlining getting the wrong begin lifetime
|
|
// block (which in this case is the entry block).
|
|
let model = Model()
|
|
model.selectedContact = nil
|
|
}
|