From f2ffd3771e3b28a284f9f1589abcee14b020c5fc Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Wed, 17 Sep 2025 12:38:23 -0700 Subject: [PATCH 1/2] [Embedded] Enable Embedded Swift restrictions diagnostics (as warnings) in embedded builds These restrictions will generally manifest as failures of various forms later in the compiler process. Enable the diagnostics to give earlier feedback to help stay within the bounds of Embedded Swift. Fixes rdar://121205043. --- lib/Frontend/CompilerInvocation.cpp | 23 +++++++++++++++++++++++ test/embedded/restrictions.swift | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index acb6cf8688adc..879ec30ea098f 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -2522,6 +2522,21 @@ static bool ParseSearchPathArgs(SearchPathOptions &Opts, ArgList &Args, return false; } +/// Determine whether the given argument list enables Embedded Swift. +static bool isEmbedded(ArgList &args) { + using namespace swift::options; + + for (const Arg *arg : args.filtered_reverse( + OPT_enable_experimental_feature, OPT_disable_experimental_feature)) { + if (llvm::StringRef(arg->getValue()) != "Embedded") + continue; + + return arg->getOption().matches(OPT_enable_experimental_feature); + } + + return false; +} + static bool ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, DiagnosticEngine &Diags) { // NOTE: This executes at the beginning of parsing the command line and cannot @@ -2589,6 +2604,14 @@ static bool ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, } } + // If the "embedded" flag was provided, enable the EmbeddedRestrictions + // warning group. This group is opt-in in non-Embedded builds. + if (isEmbedded(Args)) { + Opts.WarningsAsErrorsRules.push_back( + WarningAsErrorRule(WarningAsErrorRule::Action::Disable, + "EmbeddedRestrictions")); + } + Opts.SuppressWarnings |= Args.hasArg(OPT_suppress_warnings); Opts.SuppressRemarks |= Args.hasArg(OPT_suppress_remarks); for (const Arg *arg : Args.filtered(OPT_warning_treating_Group)) { diff --git a/test/embedded/restrictions.swift b/test/embedded/restrictions.swift index 4046dded30ef6..3dea3d3aced8b 100644 --- a/test/embedded/restrictions.swift +++ b/test/embedded/restrictions.swift @@ -1,5 +1,5 @@ // RUN: %target-typecheck-verify-swift -Wwarning EmbeddedRestrictions -verify-additional-prefix nonembedded- -// RUN: %target-typecheck-verify-swift -Wwarning EmbeddedRestrictions -enable-experimental-feature Embedded -verify-additional-prefix embedded- +// RUN: %target-typecheck-verify-swift -enable-experimental-feature Embedded -verify-additional-prefix embedded- // REQUIRES: swift_in_compiler // REQUIRES: swift_feature_Embedded From 7088022eef738913989b3df87ac1bf3463a7359b Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Wed, 17 Sep 2025 13:04:41 -0700 Subject: [PATCH 2/2] [Standard library] Eliminate ABI-only rethrows versions from Embedded Where we have rethrowing versions of functions that have typed-throws counterparts that are only retained for ABI compatibility, wrap them in `#if !$Embedded` so they aren't compiled into the Embedded version of the standard library. This eliminates warnings about this code, which cannot actually be used with arbitrary errors anyway. --- stdlib/public/core/Array.swift | 2 ++ stdlib/public/core/ArrayBufferProtocol.swift | 4 ++++ stdlib/public/core/Collection.swift | 2 ++ stdlib/public/core/ExistentialCollection.swift | 8 ++++++++ stdlib/public/core/LifetimeManager.swift | 4 ++++ stdlib/public/core/Sequence.swift | 2 ++ stdlib/public/core/UnsafeRawBufferPointer.swift.gyb | 6 ++++++ 7 files changed, 28 insertions(+) diff --git a/stdlib/public/core/Array.swift b/stdlib/public/core/Array.swift index 9f68b1180f803..bd63bcff26a7f 100644 --- a/stdlib/public/core/Array.swift +++ b/stdlib/public/core/Array.swift @@ -1509,6 +1509,7 @@ extension Array { } extension Array { +#if !$Embedded /// Implementation preserved (for ABI reasons) for: /// Array(unsafeUninitializedCapacity:initializingWith:) /// and ContiguousArray(unsafeUninitializedCapacity:initializingWith:) @@ -1525,6 +1526,7 @@ extension Array { initializingWithTypedThrowsInitializer: initializer ) } +#endif /// Implementation for: /// Array(unsafeUninitializedCapacity:initializingWith:) diff --git a/stdlib/public/core/ArrayBufferProtocol.swift b/stdlib/public/core/ArrayBufferProtocol.swift index efc5b93088960..463913f6c2922 100644 --- a/stdlib/public/core/ArrayBufferProtocol.swift +++ b/stdlib/public/core/ArrayBufferProtocol.swift @@ -76,11 +76,13 @@ where Indices == Range { /// Returns a `_SliceBuffer` containing the elements in `bounds`. subscript(bounds: Range) -> _SliceBuffer { get } +#if !$Embedded // Superseded by the typed-throws version of this function, but retained // for ABI reasons. func withUnsafeBufferPointer( _ body: (UnsafeBufferPointer) throws -> R ) rethrows -> R +#endif /// Call `body(p)`, where `p` is an `UnsafeBufferPointer` over the /// underlying contiguous storage. If no such storage exists, it is @@ -90,11 +92,13 @@ where Indices == Range { _ body: (UnsafeBufferPointer) throws(E) -> R ) throws(E) -> R +#if !$Embedded // Superseded by the typed-throws version of this function, but retained // for ABI reasons. mutating func withUnsafeMutableBufferPointer( _ body: (UnsafeMutableBufferPointer) throws -> R ) rethrows -> R +#endif /// Call `body(p)`, where `p` is an `UnsafeMutableBufferPointer` /// over the underlying contiguous storage. diff --git a/stdlib/public/core/Collection.swift b/stdlib/public/core/Collection.swift index b56f3d15b9d6d..1e2b88ab2a99c 100644 --- a/stdlib/public/core/Collection.swift +++ b/stdlib/public/core/Collection.swift @@ -1213,6 +1213,7 @@ extension Collection { return Array(result) } +#if !$Embedded // ABI-only entrypoint for the rethrows version of map, which has been // superseded by the typed-throws version. Expressed as "throws", which is // ABI-compatible with "rethrows". @@ -1224,6 +1225,7 @@ extension Collection { ) throws -> [T] { try map(transform) } +#endif /// Returns a subsequence containing all but the given number of initial /// elements. diff --git a/stdlib/public/core/ExistentialCollection.swift b/stdlib/public/core/ExistentialCollection.swift index 13d412b8704b4..74a13344f14ac 100644 --- a/stdlib/public/core/ExistentialCollection.swift +++ b/stdlib/public/core/ExistentialCollection.swift @@ -1334,6 +1334,7 @@ extension AnySequence { } } +#if !$Embedded // ABI-only entrypoint for the rethrows version of map, which has been // superseded by the typed-throws version. Expressed as "throws", which is // ABI-compatible with "rethrows". @@ -1345,6 +1346,7 @@ extension AnySequence { ) throws -> [T] { try map(transform) } +#endif @inlinable public __consuming func filter( @@ -1438,6 +1440,7 @@ extension AnyCollection { } } +#if !$Embedded // ABI-only entrypoint for the rethrows version of map, which has been // superseded by the typed-throws version. Expressed as "throws", which is // ABI-compatible with "rethrows". @@ -1449,6 +1452,7 @@ extension AnyCollection { ) throws -> [T] { try map(transform) } +#endif @inlinable public __consuming func filter( @@ -1548,6 +1552,7 @@ extension AnyBidirectionalCollection { } } +#if !$Embedded // ABI-only entrypoint for the rethrows version of map, which has been // superseded by the typed-throws version. Expressed as "throws", which is // ABI-compatible with "rethrows". @@ -1559,6 +1564,7 @@ extension AnyBidirectionalCollection { ) throws -> [T] { try map(transform) } +#endif @inlinable public __consuming func filter( @@ -1660,6 +1666,7 @@ extension AnyRandomAccessCollection { } } +#if !$Embedded // ABI-only entrypoint for the rethrows version of map, which has been // superseded by the typed-throws version. Expressed as "throws", which is // ABI-compatible with "rethrows". @@ -1671,6 +1678,7 @@ extension AnyRandomAccessCollection { ) throws -> [T] { try map(transform) } +#endif @inlinable public __consuming func filter( diff --git a/stdlib/public/core/LifetimeManager.swift b/stdlib/public/core/LifetimeManager.swift index 4939333732dfc..8d51e453bcedc 100644 --- a/stdlib/public/core/LifetimeManager.swift +++ b/stdlib/public/core/LifetimeManager.swift @@ -184,6 +184,7 @@ public func withUnsafePointer( return try unsafe body(UnsafePointer(Builtin.addressOfBorrow(value))) } +#if !$Embedded /// ABI: Historical withUnsafePointer(to:_:) rethrows, expressed as "throws", /// which is ABI-compatible with "rethrows". @_spi(SwiftStdlibLegacyABI) @available(swift, obsoleted: 1) @@ -196,6 +197,7 @@ internal func __abi_withUnsafePointer( { return try unsafe body(UnsafePointer(Builtin.addressOfBorrow(value))) } +#endif /// Invokes the given closure with a pointer to the given argument. /// @@ -229,6 +231,7 @@ public func withUnsafePointer( try unsafe body(UnsafePointer(Builtin.addressof(&value))) } +#if !$Embedded /// ABI: Historical withUnsafePointer(to:_:) rethrows, /// expressed as "throws", which is ABI-compatible with "rethrows". @_spi(SwiftStdlibLegacyABI) @available(swift, obsoleted: 1) @@ -240,6 +243,7 @@ internal func __abi_se0413_withUnsafePointer( ) throws -> Result { return try unsafe body(UnsafePointer(Builtin.addressof(&value))) } +#endif /// Invokes the given closure with a pointer to the given argument. /// diff --git a/stdlib/public/core/Sequence.swift b/stdlib/public/core/Sequence.swift index e34bb9d8df267..5ae2e1addeaaa 100644 --- a/stdlib/public/core/Sequence.swift +++ b/stdlib/public/core/Sequence.swift @@ -705,6 +705,7 @@ extension Sequence { return Array(result) } +#if !$Embedded // ABI-only entrypoint for the rethrows version of map, which has been // superseded by the typed-throws version. Expressed as "throws", which is // ABI-compatible with "rethrows". @@ -716,6 +717,7 @@ extension Sequence { ) throws -> [T] { try map(transform) } +#endif /// Returns an array containing, in order, the elements of the sequence /// that satisfy the given predicate. diff --git a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb index d6e4b7da6bb04..24e7272f5a8c9 100644 --- a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb @@ -1278,6 +1278,7 @@ public func withUnsafeMutableBytes( return try unsafe body(unsafe .init(start: pointer, count: MemoryLayout.size)) } +#if !$Embedded /// ABI: Historical withUnsafeMutableBytes(of:_:) rethrows, /// expressed as "throws", which is ABI-compatible with "rethrows". @_spi(SwiftStdlibLegacyABI) @available(swift, obsoleted: 1) @@ -1292,6 +1293,7 @@ func __abi_se0413_withUnsafeMutableBytes( start: $0, count: MemoryLayout.size)) } } +#endif /// Invokes the given closure with a buffer pointer covering the raw bytes of /// the given argument. @@ -1345,6 +1347,7 @@ public func withUnsafeBytes( return try unsafe body(unsafe .init(start: address, count: MemoryLayout.size)) } +#if !$Embedded /// ABI: Historical withUnsafeBytes(of:_:) rethrows, /// expressed as "throws", which is ABI-compatible with "rethrows". @_spi(SwiftStdlibLegacyABI) @available(swift, obsoleted: 1) @@ -1358,6 +1361,7 @@ func __abi_se0413_withUnsafeBytes( try unsafe body(unsafe UnsafeRawBufferPointer(start: $0, count: MemoryLayout.size)) } } +#endif /// Invokes the given closure with a buffer pointer covering the raw bytes of /// the given argument. @@ -1409,6 +1413,7 @@ public func withUnsafeBytes< return try unsafe body(unsafe .init(start: addr, count: MemoryLayout.size)) } +#if !$Embedded /// ABI: Historical withUnsafeBytes(of:_:) rethrows, /// expressed as "throws", which is ABI-compatible with "rethrows". @_spi(SwiftStdlibLegacyABI) @available(swift, obsoleted: 1) @@ -1422,6 +1427,7 @@ func __abi_se0413_withUnsafeBytes( let buffer = unsafe UnsafeRawBufferPointer(start: addr, count: MemoryLayout.size) return try unsafe body(buffer) } +#endif /// Invokes the given closure with a buffer pointer covering the raw bytes of /// the given argument.