Swift 6 Strict Concurrency: Unresolved Behavior of nonisolated(unsafe) in Actor Captures
0 reputation · 26 Jul 2025, 07:47 UTC
0 reputation · 26 Jul 2025, 07:47 UTC
The Swift 6 language mode turns the compiler into a full data‑race safety checker. Any cross‑actor capture that does not satisfy the Sendable protocol becomes a hard error. The @nonisolated(unsafe) attribute provides an escape hatch, allowing a reference to be used outside its actor without the compiler enforcing isolation. However, the language does not yet offer a static verification that an unsafe reference is truly data‑race free. This creates a manual audit gap for developers migrating large codebases to Swift 6.
When upgrading from Swift 5.10 to Swift 6, projects can opt in via the swift-tools-version and language mode settings. The transition introduces incremental warnings in 5.9‑5.10 and hard errors in 6, affecting library compatibility and ABI stability.
What guarantees, if any, does @nonisolated(unsafe) provide for data‑race safety when a reference is captured by an actor? Can the compiler detect unsafe captures, or must developers rely solely on manual audits? How does adding @unchecked Sendable to a type influence downstream consumers and ABI compatibility?
29275 reputation · 26 Jul 2025, 15:00 UTC
@nonisolated(unsafe) provides no static guarantee that a captured reference is free of data races. It merely silences the compiler’s Sendable check for that specific reference, allowing it to be accessed from any concurrency domain without isolation. Safety must be ensured by the programmer through manual review or runtime tools.
The compiler cannot detect** whether an unsafe capture is actually race‑free; it only verifies the presence of the attribute. Detection of unsafe captures therefore relies on manual audit or external tools such as Thread Sanitizer.
Marking a type with @unchecked Sendable opts the type out of Sendable checking entirely. Downstream code treats the type as Sendable, propagating the unsafe assumption, while the type’s memory layout remains unchanged and only the Sendable witness table is omitted from the ABI.
@unchecked Sendable mirrors the same opt‑out principle at the type level, removing the conformance witness but leaving the type’s layout intact.@nonisolated(unsafe) suppresses the Sendable diagnostic for the annotated expression; no further static analysis is performed.@unchecked Sendable, the generated SIL omits the Sendable conformance witness table, but the type’s field layout and size are unchanged.# 1. Build with Swift 6 toolchain and strict concurrency
swiftc -strict-concurrency=complete -target x86_64-apple-macosx14.0 YourFile.swift
# 2. Capture a non‑Sendable class in an actor closure without any attribute → expect error
# 3. Add @nonisolated(unsafe) to the capture → error disappears
# 4. Run the resulting binary under Thread Sanitizer to see if a race is reported
# 5. To inspect the ABI effect of @unchecked Sendable:
swiftc -emit-sil -target x86_64-apple-macosx14.0 YourFile.swift | grep -A2 -B2 'Sendable'
Is the captured reference mutable or immutable? If the reference is immutable (or only read‑only after initialization), the risk of a data race is lower, and the unsafe attribute may be acceptable with less extensive manual review. If the reference is mutable, a thorough audit or runtime sanitizer is strongly advised.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.