Skip to content

Allow building under library evolution on Xcode 26.5 / Swift 6.3#93

Open
leogdion wants to merge 1 commit into
apple:mainfrom
brightdigit:fix/library-evolution-inlinable-deinit
Open

Allow building under library evolution on Xcode 26.5 / Swift 6.3#93
leogdion wants to merge 1 commit into
apple:mainfrom
brightdigit:fix/library-evolution-inlinable-deinit

Conversation

@leogdion

@leogdion leogdion commented Jun 2, 2026

Copy link
Copy Markdown

Motivation

Building this package with library evolution enabled (-enable-library-evolution / BUILD_LIBRARY_FOR_DISTRIBUTION=YES) fails on Xcode 26.5 / Swift 6.3:

Lock.swift: error: deinitializer can only be '@inlinable' if the class is '@_fixed_layout'
Lock.swift: error: 'let' property '_storage' may not be initialized directly; use "self.init(...)" or "self = ..." instead

This affects consumers that vend OpenAPIURLSession (transitively) inside a framework archived for binary distribution. See #92 for full details and reproduction.

Modifications

LockStorage.deinit and the Lock / LockedValueBox initializers are @inlinable while their enclosing types are not @_fixed_layout / @frozen. Under library evolution Swift 6.3 now rejects that.

This change gates those three @inlinable attributes behind a new compilation condition, OPENAPIURLSESSION_NONINLINABLE_DEINIT:

  • Default build (flag unset): byte-for-byte identical to today — the @inlinable attributes remain.
  • Resilient build (flag set): consumers building under library evolution can define OPENAPIURLSESSION_NONINLINABLE_DEINIT (e.g. via SWIFT_ACTIVE_COMPILATION_CONDITIONS) to drop the attributes and compile cleanly.

This keeps the optimization for everyone who doesn't need resilience, and unblocks those who do, without forcing a layout decision on the package.

Maintainers may instead prefer marking LockStorage @_fixed_layout and Lock / LockedValueBox @frozen, which fixes the same errors with no consumer opt-in — happy to switch this PR to that approach if preferred.

Result

swift build -Xswiftc -enable-library-evolution -Xswiftc -DOPENAPIURLSESSION_NONINLINABLE_DEINIT succeeds; the default swift build and swift build -Xswiftc -enable-library-evolution (without the flag) are unchanged.

Test Plan

  • swift build — unchanged, succeeds.
  • swift build -Xswiftc -enable-library-evolution — still reproduces the original errors (no behavior change by default).
  • swift build -Xswiftc -enable-library-evolution -Xswiftc -DOPENAPIURLSESSION_NONINLINABLE_DEINIT — compiles successfully.
  • Verified end-to-end by archiving a multi-platform XCFramework (macOS + watchOS) with BUILD_LIBRARY_FOR_DISTRIBUTION=YES and the flag set.

Resolves #92.

Under `-enable-library-evolution` (BUILD_LIBRARY_FOR_DISTRIBUTION=YES),
Swift 6.3+ rejects:
  - `@inlinable` deinit on a non-`@_fixed_layout` class (LockStorage)
  - `@inlinable` initializers that directly initialize a stored `let`
    property of a non-`@frozen` struct (Lock, LockedValueBox)

Gate those `@inlinable` attributes behind the
OPENAPIURLSESSION_NONINLINABLE_LOCK compilation condition so consumers
that build this package resiliently can opt out, while the default build
is byte-for-byte unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@leogdion leogdion force-pushed the fix/library-evolution-inlinable-deinit branch from f0fd206 to 4f69148 Compare June 2, 2026 13:25
@guoye-zhang

Copy link
Copy Markdown
Contributor

@simonjbeaumont This file was copied from somewhere right? Since this will be replaced with Mutex, maybe marking it as frozen is fine?

@leogdion

leogdion commented Jun 2, 2026

Copy link
Copy Markdown
Author

@simonjbeaumont This file was copied from somewhere right? Since this will be replaced with Mutex, maybe marking it as frozen is fine?

I am not sure where the Mutex is at as far Swift Version compatibility but my XCFramework is targeting Swift 5.10

@simonjbeaumont

Copy link
Copy Markdown
Collaborator

@guoye-zhang wrote:

@simonjbeaumont This file was copied from somewhere right? Since this will be replaced with Mutex, maybe marking it as frozen is fine?

We vendored this one in from NIO. Once Swift 6.2 is the floor, we can move to Mutex, yeah, but that will be when 6.4 is released.

@leogdion wrote:

I am not sure where the Mutex is at as far Swift Version compatibility but my XCFramework is targeting Swift 5.10

The minimum supported Swift version for this package is already 6.1 and rolls forward with a latest-three-version window.

More generally, we don't typically support compiling with library evolution mode in our repos (related discussion in NIO: apple/swift-nio#1257) and we don't guarantee ABI stability (only API).

I'm concerned that what you want to do might work now, but won't be guaranteed to continue working.

@leogdion

leogdion commented Jun 3, 2026

Copy link
Copy Markdown
Author

@guoye-zhang wrote:

@simonjbeaumont This file was copied from somewhere right? Since this will be replaced with Mutex, maybe marking it as frozen is fine?

We vendored this one in from NIO. Once Swift 6.2 is the floor, we can move to Mutex, yeah, but that will be when 6.4 is released.

@leogdion wrote:

I am not sure where the Mutex is at as far Swift Version compatibility but my XCFramework is targeting Swift 5.10

The minimum supported Swift version for this package is already 6.1 and rolls forward with a latest-three-version window.

More generally, we don't typically support compiling with library evolution mode in our repos (related discussion in NIO: apple/swift-nio#1257) and we don't guarantee ABI stability (only API).

I'm concerned that what you want to do might work now, but won't be guaranteed to continue working.

Thanks @simonjbeaumont for the context. I think there's a valid reason to support library evolution mode for client side pieces (iOS, etc...) as opposed to server side pieces so that's where I think this URLSession library is more valid. I also made sure to gate this by a OPENAPIURLSESSION_NONINLINABLE_LOCK flag too.

I guess if the Lock is removed at some point this won't be an issue any more.

Or course I'm open to workarounds. We deliver an XCFramework to our client and we use this package - that's the crux of the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Library-evolution build fails on Xcode 26.5 / Swift 6.3: @inlinable deinit/inits in Lock.swift require @_fixed_layout/@frozen

3 participants