diff --git a/lib/Sema/ResilienceDiagnostics.cpp b/lib/Sema/ResilienceDiagnostics.cpp index b24213d8778a1..d4e1c45a35f36 100644 --- a/lib/Sema/ResilienceDiagnostics.cpp +++ b/lib/Sema/ResilienceDiagnostics.cpp @@ -98,11 +98,8 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc, } // Embedded functions can reference non-public decls as they are visible - // to clients. Still report references to decls imported non-publicly - // to enforce access-level on imports. - ImportAccessLevel problematicImport = D->getImportAccessFrom(DC); - if (fragileKind.kind == FragileFunctionKind::EmbeddedAlwaysEmitIntoClient && - !problematicImport) + // to clients. + if (fragileKind.kind == FragileFunctionKind::EmbeddedAlwaysEmitIntoClient) return false; DowngradeToWarning downgradeToWarning = DowngradeToWarning::No; @@ -135,6 +132,7 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc, Context.Diags.diagnose(D, diag::resilience_decl_declared_here, D); + ImportAccessLevel problematicImport = D->getImportAccessFrom(DC); if (problematicImport.has_value() && problematicImport->accessLevel < D->getFormalAccess()) { Context.Diags.diagnose(problematicImport->importLoc, @@ -298,6 +296,7 @@ static bool diagnoseValueDeclRefExportability(SourceLoc loc, const ValueDecl *D, } }); + auto fragileKind = where.getFragileFunctionKind(); switch (originKind) { case DisallowedOriginKind::None: // The decl does not come from a source that needs to be checked for @@ -329,11 +328,15 @@ static bool diagnoseValueDeclRefExportability(SourceLoc loc, const ValueDecl *D, if (reason && reason == ExportabilityReason::AvailableAttribute && ctx.LangOpts.LibraryLevel == LibraryLevel::API) return false; - break; + LLVM_FALLTHROUGH; - case DisallowedOriginKind::ImplementationOnly: case DisallowedOriginKind::SPIImported: case DisallowedOriginKind::SPILocal: + if (fragileKind.kind == FragileFunctionKind::EmbeddedAlwaysEmitIntoClient) + return false; + break; + + case DisallowedOriginKind::ImplementationOnly: case DisallowedOriginKind::FragileCxxAPI: break; } @@ -345,7 +348,6 @@ static bool diagnoseValueDeclRefExportability(SourceLoc loc, const ValueDecl *D, return false; } - auto fragileKind = where.getFragileFunctionKind(); if (fragileKind.kind == FragileFunctionKind::None) { DiagnosticBehavior limit = downgradeToWarning == DowngradeToWarning::Yes ? DiagnosticBehavior::Warning diff --git a/test/Sema/Inputs/implementation-only-imports/indirects.swift b/test/Sema/Inputs/implementation-only-imports/indirects.swift index 08becd28d7dec..ef344ae131b2f 100644 --- a/test/Sema/Inputs/implementation-only-imports/indirects.swift +++ b/test/Sema/Inputs/implementation-only-imports/indirects.swift @@ -6,3 +6,5 @@ public typealias GenericAliasFromIndirect = (StructFromIndirect, T) public func globalFunctionFromIndirect() {} public var globalVariableFromIndirect = 0 + +@_spi(S) public func spiFunctionFromDirect() {} diff --git a/test/Sema/access-level-and-implementation-only-import-embedded.swift b/test/Sema/access-level-and-implementation-only-import-embedded.swift new file mode 100644 index 0000000000000..a70418774aa37 --- /dev/null +++ b/test/Sema/access-level-and-implementation-only-import-embedded.swift @@ -0,0 +1,182 @@ +/// Test @_implementationOnly internal import exportability diagnostics in embedded mode. + +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -o %t/indirects.swiftmodule \ +// RUN: %S/Inputs/implementation-only-imports/indirects.swift \ +// RUN: -swift-version 5 -target arm64-apple-none-macho \ +// RUN: -enable-experimental-feature Embedded +// RUN: %target-swift-frontend -emit-module -o %t/directs.swiftmodule -I %t \ +// RUN: %S/Inputs/implementation-only-imports/directs.swift \ +// RUN: -swift-version 5 -target arm64-apple-none-macho \ +// RUN: -enable-experimental-feature Embedded + +// RUN: %target-swift-frontend -typecheck -verify -verify-ignore-unrelated %s -I %t \ +// RUN: -swift-version 5 -target arm64-apple-none-macho \ +// RUN: -enable-experimental-feature Embedded + +// REQUIRES: swift_feature_Embedded +// REQUIRES: embedded_stdlib_cross_compiling + +@_implementationOnly internal import directs +// expected-warning @-1 {{using '@_implementationOnly' without enabling library evolution for 'main' may lead to instability during execution}} +// expected-note @-2 11 {{struct 'StructFromDirect' imported as 'internal' from 'directs' here}} +// expected-note @-3 6 {{initializer 'init()' imported as 'internal' from 'directs' here}} +import indirects + +internal func localInternalFunc() {} // expected-note {{global function 'localInternalFunc()' is not '@usableFromInline' or public}} + +@inlinable +public func explicitlyInlinable(arg: StructFromDirect = StructFromDirect()) { +// expected-error @-1 {{initializer 'init()' is internal and cannot be referenced from a default argument value}} +// expected-error @-2 {{struct 'StructFromDirect' is internal and cannot be referenced from a default argument value}} +// expected-error @-3 {{struct 'StructFromDirect' is internal and cannot be referenced from an '@inlinable' function}} +// expected-error @-4 {{function cannot be declared public because its parameter uses an internal type}} +// expected-note @-5 {{struct 'StructFromDirect' is imported by this file as 'internal' from 'directs'}} + _ = StructFromDirect() // expected-error {{initializer 'init()' is internal and cannot be referenced from an '@inlinable' function}} + // expected-error@-1 {{struct 'StructFromDirect' is internal and cannot be referenced from an '@inlinable' function}} + + if (true) { + _ = StructFromDirect() // expected-error {{initializer 'init()' is internal and cannot be referenced from an '@inlinable' function}} + // expected-error@-1 {{struct 'StructFromDirect' is internal and cannot be referenced from an '@inlinable' function}} + } + + func nested() { + _ = StructFromDirect() // expected-error {{initializer 'init()' is internal and cannot be referenced from an '@inlinable' function}} + // expected-error@-1 {{struct 'StructFromDirect' is internal and cannot be referenced from an '@inlinable' function}} + } + nested() + + localInternalFunc() // expected-error {{global function 'localInternalFunc()' is internal and cannot be referenced from an '@inlinable' function}} + + explicitlyInlinable() + implicitlyInlinablePublic() + implicitlyInlinablePrivate() // expected-error {{global function 'implicitlyInlinablePrivate(arg:)' is private and cannot be referenced from an '@inlinable' function}} + explicitNonInliable() +} + +public func implicitlyInlinablePublic(arg: StructFromDirect = StructFromDirect()) { +// expected-error @-1 {{initializer 'init()' is internal and cannot be referenced from a default argument value}} +// expected-error @-2 {{struct 'StructFromDirect' is internal and cannot be referenced from a default argument value}} +// expected-error @-3 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} +// expected-error @-4 {{function cannot be declared public because its parameter uses an internal type}} +// expected-note @-5 {{struct 'StructFromDirect' is imported by this file as 'internal' from 'directs'}} + _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + + if (true) { + _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + } + + func nested() { + _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + } + nested() + + localInternalFunc() + + explicitlyInlinable() + implicitlyInlinablePublic() + implicitlyInlinablePrivate() + explicitNonInliable() +} + +private func implicitlyInlinablePrivate(arg: StructFromDirect = StructFromDirect()) { +// expected-error @-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} +// expected-note @-2 {{global function 'implicitlyInlinablePrivate(arg:)' is not '@usableFromInline' or public}} + _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + + if (true) { + _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + } + + func nested() { + _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + } + nested() + + localInternalFunc() + + explicitlyInlinable() + implicitlyInlinablePublic() + implicitlyInlinablePrivate() + explicitNonInliable() +} + +@_neverEmitIntoClient +public func explicitNonInliable(arg: StructFromDirect = StructFromDirect()) { +// expected-error @-1 {{initializer 'init()' is internal and cannot be referenced from a default argument value}} +// expected-error @-2 {{struct 'StructFromDirect' is internal and cannot be referenced from a default argument value}} +// expected-error @-3 {{cannot use struct 'StructFromDirect' here; 'directs' has been imported as implementation-only}} +// expected-error @-4 {{function cannot be declared public because its parameter uses an internal type}} +// expected-note @-5 {{struct 'StructFromDirect' is imported by this file as 'internal' from 'directs'}} + _ = StructFromDirect() + + if (true) { + _ = StructFromDirect() + } + + @_neverEmitIntoClient + func nested() { + _ = StructFromDirect() + } + nested() + + localInternalFunc() + + explicitlyInlinable() + implicitlyInlinablePublic() + implicitlyInlinablePrivate() + explicitNonInliable() +} + +@_neverEmitIntoClient +internal func explicitNonInliableInternal(arg: StructFromDirect = StructFromDirect()) { + _ = StructFromDirect() + + if (true) { + _ = StructFromDirect() + } + + @_neverEmitIntoClient + func nested() { + _ = StructFromDirect() + } + nested() + + localInternalFunc() + + explicitlyInlinable() + implicitlyInlinablePublic() + implicitlyInlinablePrivate() + explicitNonInliable() +} + +public func legalAccessToIndirect(arg: StructFromIndirect = StructFromIndirect()) { + _ = StructFromIndirect() + + if (true) { + _ = StructFromIndirect() + } + + func nested() { + _ = StructFromIndirect() + } + nested() +} + +public struct ExposedLayoutPublic { + public var publicField: StructFromDirect // expected-error {{property cannot be declared public because its type uses an internal type}} + // expected-error @-1 {{cannot use struct 'StructFromDirect' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; 'directs' has been imported as implementation-only}} + // expected-note @-2 {{struct 'StructFromDirect' is imported by this file as 'internal' from 'directs'}} + + private var privateField: StructFromDirect +} + +private struct ExposedLayoutPrivate { + private var privateField: StructFromDirect +} diff --git a/test/Sema/access-level-import-embedded.swift b/test/Sema/access-level-import-embedded.swift index feae382564d98..dc78227b2d056 100644 --- a/test/Sema/access-level-import-embedded.swift +++ b/test/Sema/access-level-import-embedded.swift @@ -17,10 +17,9 @@ // REQUIRES: swift_feature_Embedded // REQUIRES: embedded_stdlib_cross_compiling -@_implementationOnly internal import directs -// expected-warning @-1 {{using '@_implementationOnly' without enabling library evolution for 'main' may lead to instability during execution}} -// expected-note @-2 19 {{struct 'StructFromDirect' imported as 'internal' from 'directs' here}} -// expected-note @-3 12 {{initializer 'init()' imported as 'internal' from 'directs' here}} +internal import directs +// expected-note @-1 11 {{struct 'StructFromDirect' imported as 'internal' from 'directs' here}} +// expected-note @-2 6 {{initializer 'init()' imported as 'internal' from 'directs' here}} import indirects internal func localInternalFunc() {} // expected-note {{global function 'localInternalFunc()' is not '@usableFromInline' or public}} @@ -50,27 +49,23 @@ public func explicitlyInlinable(arg: StructFromDirect = StructFromDirect()) { explicitlyInlinable() implicitlyInlinablePublic() - implicitlyInlinablePrivate() // expected-error {{global function 'implicitlyInlinablePrivate(arg:)' is private and cannot be referenced from an '@inlinable' function}} + implicitlyInlinablePrivate() // expected-error {{global function 'implicitlyInlinablePrivate(arg:)' is internal and cannot be referenced from an '@inlinable' function}} explicitNonInliable() } public func implicitlyInlinablePublic(arg: StructFromDirect = StructFromDirect()) { // expected-error @-1 {{initializer 'init()' is internal and cannot be referenced from a default argument value}} // expected-error @-2 {{struct 'StructFromDirect' is internal and cannot be referenced from a default argument value}} -// expected-error @-3 {{struct 'StructFromDirect' is internal and cannot be referenced from an embedded function not marked '@_neverEmitIntoClient'}} -// expected-error @-4 {{function cannot be declared public because its parameter uses an internal type}} -// expected-note @-5 {{struct 'StructFromDirect' is imported by this file as 'internal' from 'directs'}} - _ = StructFromDirect() // expected-error {{initializer 'init()' is internal and cannot be referenced from an embedded function not marked '@_neverEmitIntoClient'}} - // expected-error@-1 {{struct 'StructFromDirect' is internal and cannot be referenced from an embedded function not marked '@_neverEmitIntoClient'}} +// expected-error @-3 {{function cannot be declared public because its parameter uses an internal type}} +// expected-note @-4 {{struct 'StructFromDirect' is imported by this file as 'internal' from 'directs'}} + _ = StructFromDirect() if (true) { - _ = StructFromDirect() // expected-error {{initializer 'init()' is internal and cannot be referenced from an embedded function not marked '@_neverEmitIntoClient'}} - // expected-error@-1 {{struct 'StructFromDirect' is internal and cannot be referenced from an embedded function not marked '@_neverEmitIntoClient'}} + _ = StructFromDirect() } func nested() { - _ = StructFromDirect() // expected-error {{initializer 'init()' is internal and cannot be referenced from an embedded function not marked '@_neverEmitIntoClient'}} - // expected-error@-1 {{struct 'StructFromDirect' is internal and cannot be referenced from an embedded function not marked '@_neverEmitIntoClient'}} + _ = StructFromDirect() } nested() @@ -82,20 +77,16 @@ public func implicitlyInlinablePublic(arg: StructFromDirect = StructFromDirect() explicitNonInliable() } -private func implicitlyInlinablePrivate(arg: StructFromDirect = StructFromDirect()) { -// expected-error @-1 {{struct 'StructFromDirect' is internal and cannot be referenced from an embedded function not marked '@_neverEmitIntoClient'}} -// expected-note @-2 {{global function 'implicitlyInlinablePrivate(arg:)' is not '@usableFromInline' or public}} - _ = StructFromDirect() // expected-error {{initializer 'init()' is internal and cannot be referenced from an embedded function not marked '@_neverEmitIntoClient'}} - // expected-error@-1 {{struct 'StructFromDirect' is internal and cannot be referenced from an embedded function not marked '@_neverEmitIntoClient'}} +internal func implicitlyInlinablePrivate(arg: StructFromDirect = StructFromDirect()) { +// expected-note @-1 {{global function 'implicitlyInlinablePrivate(arg:)' is not '@usableFromInline' or public}} + _ = StructFromDirect() if (true) { - _ = StructFromDirect() // expected-error {{initializer 'init()' is internal and cannot be referenced from an embedded function not marked '@_neverEmitIntoClient'}} - // expected-error@-1 {{struct 'StructFromDirect' is internal and cannot be referenced from an embedded function not marked '@_neverEmitIntoClient'}} + _ = StructFromDirect() } func nested() { - _ = StructFromDirect() // expected-error {{initializer 'init()' is internal and cannot be referenced from an embedded function not marked '@_neverEmitIntoClient'}} - // expected-error@-1 {{struct 'StructFromDirect' is internal and cannot be referenced from an embedded function not marked '@_neverEmitIntoClient'}} + _ = StructFromDirect() } nested() @@ -111,9 +102,8 @@ private func implicitlyInlinablePrivate(arg: StructFromDirect = StructFromDirect public func explicitNonInliable(arg: StructFromDirect = StructFromDirect()) { // expected-error @-1 {{initializer 'init()' is internal and cannot be referenced from a default argument value}} // expected-error @-2 {{struct 'StructFromDirect' is internal and cannot be referenced from a default argument value}} -// expected-error @-3 {{cannot use struct 'StructFromDirect' here; 'directs' has been imported as implementation-only}} -// expected-error @-4 {{function cannot be declared public because its parameter uses an internal type}} -// expected-note @-5 {{struct 'StructFromDirect' is imported by this file as 'internal' from 'directs'}} +// expected-error @-3 {{function cannot be declared public because its parameter uses an internal type}} +// expected-note @-4 {{struct 'StructFromDirect' is imported by this file as 'internal' from 'directs'}} _ = StructFromDirect() if (true) { @@ -171,12 +161,11 @@ public func legalAccessToIndirect(arg: StructFromIndirect = StructFromIndirect() public struct ExposedLayoutPublic { public var publicField: StructFromDirect // expected-error {{property cannot be declared public because its type uses an internal type}} - // expected-error @-1 {{cannot use struct 'StructFromDirect' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; 'directs' has been imported as implementation-only}} - // expected-note @-2 {{struct 'StructFromDirect' is imported by this file as 'internal' from 'directs'}} + // expected-note @-1 {{struct 'StructFromDirect' is imported by this file as 'internal' from 'directs'}} - private var privateField: StructFromDirect + internal var privateField: StructFromDirect } -private struct ExposedLayoutPrivate { - private var privateField: StructFromDirect +internal struct ExposedLayoutPrivate { + internal var privateField: StructFromDirect } diff --git a/test/Sema/implementation-only-import-embedded.swift b/test/Sema/implementation-only-import-embedded.swift index 49ebf9f0aa568..38ee43a9b5f04 100644 --- a/test/Sema/implementation-only-import-embedded.swift +++ b/test/Sema/implementation-only-import-embedded.swift @@ -11,7 +11,7 @@ // RUN: -enable-experimental-feature Embedded // RUN: %target-swift-frontend -typecheck -verify -verify-ignore-unrelated %s -I %t \ -// RUN: -swift-version 5 -target arm64-apple-none-macho \ +// RUN: -swift-version 6 -target arm64-apple-none-macho \ // RUN: -define-availability "availMacro:macOS 26.0, iOS 26.0" \ // RUN: -enable-experimental-feature Embedded @@ -20,10 +20,12 @@ @_implementationOnly import directs // expected-warning @-1 {{using '@_implementationOnly' without enabling library evolution for 'main' may lead to instability during execution}} -import indirects +@_spi(S) @_spiOnly import indirects internal func localInternalFunc() {} // expected-note {{global function 'localInternalFunc()' is not '@usableFromInline' or public}} +@_spi(S) public func localSPI() {} + @inlinable public func explicitlyInlinable(arg: StructFromDirect = StructFromDirect()) { // expected-error @-1 {{initializer 'init()' cannot be used in a default argument value because 'directs' was imported implementation-only}} @@ -77,6 +79,9 @@ public func implicitlyInlinablePublic(arg: StructFromDirect = StructFromDirect() explicitNonInliable() if #available(availMacro, *) { } + + localSPI() + spiFunctionFromDirect() } private func implicitlyInlinablePrivate(arg: StructFromDirect = StructFromDirect()) { @@ -186,6 +191,7 @@ struct Accessors { } } +@_spi(S) public func legalAccessToIndirect(arg: StructFromIndirect = StructFromIndirect()) { _ = StructFromIndirect()