Open
Description
Description
Since Swift does not allow weak let
bindings, it seems that weak
closure captures are always mutable and are stored in a heap-allocated box. Re-capturing mutable weak
shares heap-allocated box between closures, but if original closure is @Sendable
this sharing is ignored by the isolation checker.
Issue reproduces only when outer closure is @Sendable
. When @Sendable
is removed, data race error is reported as expected:
Task {
`- error: passing closure as a 'sending' parameter risks causing data races between code in the current task and concurrent execution of the closure
x?.bar()
`- note: closure captures 'x' which is accessible to code in the current task
}
Some users have reported that attached code crashes, though non-deterministically.
See discussion in https://forums.swift.org/t/weak-captures-in-sendable-sending-closures/78498
Reproduction
final class X: Sendable {
func bar() {}
}
func doIt(_ block: @Sendable () -> Void) { // Removing @Sendable makes race visible
block()
}
func foo() {
let x = X()
doIt { [weak x] in
Task {
x?.bar()
}
x = nil
}
}
Expected behavior
Data race error produced regardless of the sensibility of the outer closure.
Environment
$ xcrun swiftc -version
swift-driver version: 1.115 Apple Swift version 6.0.2 (swiftlang-6.0.2.1.2 clang-1600.0.26.4)
Target: arm64-apple-macosx15.0
Additional information
No response