Skip to content

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

@leogdion

Description

@leogdion

Summary

We ship a binary XCFramework that bundles OpenAPIURLSession (used internally for REST API calls), and that XCFramework is distributed to React Native developers who integrate it into their apps.

Because those developers build against our prebuilt binary with their own (often older) Xcode/Swift toolchains, we need module stability — i.e. BUILD_LIBRARY_FOR_DISTRIBUTION=YES — so the framework keeps working across compiler versions. That's exactly the configuration that propagates library evolution to OpenAPIURLSession and trips the errors above.

Building OpenAPIURLSession with library evolution enabled (-enable-library-evolution / BUILD_LIBRARY_FOR_DISTRIBUTION=YES) fails to compile on Xcode 26.5 / Swift 6.3. This happens when the package is a (transitive) dependency of a framework that is archived for binary distribution as an XCFramework. The same configuration compiled on earlier toolchains, so this is a regression triggered by the newer compiler's stricter enforcement.

Environment

  • Xcode 26.5 (build 17F42)
  • Apple Swift 6.3.2 (swiftlang-6.3.2.1.108, clang-2100.1.1.101)
  • swift-openapi-urlsession main (the constructs below are present in all 1.0.0–1.3.0 releases)

Errors

Sources/OpenAPIURLSession/BufferedStream/Lock.swift:190:5: error: deinitializer can only be '@inlinable' if the class is '@_fixed_layout'
Sources/OpenAPIURLSession/BufferedStream/Lock.swift:244:14: error: 'let' property '_storage' may not be initialized directly; use "self.init(...)" or "self = ..." instead
Sources/OpenAPIURLSession/BufferedStream/Lock.swift:322:14: error: 'let' property '_storage' may not be initialized directly; use "self.init(...)" or "self = ..." instead

Reproduction

swift build -Xswiftc -enable-library-evolution

Cause

In Sources/OpenAPIURLSession/BufferedStream/Lock.swift:

  • LockStorage (a final class) declares an @inlinable deinit.
  • Lock and LockedValueBox (structs) declare @inlinable initializers that directly initialize their stored let _storage property.

Under library evolution, types have resilient (non-fixed) layout, so the compiler requires @_fixed_layout (class) / @frozen (struct) before allowing an @inlinable deinit or an @inlinable initializer that directly assigns a stored property.

Possible fixes

  1. Mark LockStorage @_fixed_layout and Lock / LockedValueBox @frozen — keeps the @inlinable optimizations and requires no opt-in from consumers.
  2. Drop @inlinable from those three members (negligible perf impact — a lock's deinit/init are not hot paths).

A PR follows with option (2) gated behind a compilation condition so the default build is byte-for-byte unchanged, but maintainers may prefer option (1).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions