diff --git a/include/swift/AST/DeclContext.h b/include/swift/AST/DeclContext.h index b064f05cfd95d..5076540e8e0a3 100644 --- a/include/swift/AST/DeclContext.h +++ b/include/swift/AST/DeclContext.h @@ -202,7 +202,7 @@ struct ConformanceDiagnostic { ProtocolDecl *ExistingExplicitProtocol; }; -/// Used in diagnostic %selects. +/// Used in diagnostic %selects via FRAGILE_FUNC_KIND. struct FragileFunctionKind { enum Kind : unsigned { Transparent, @@ -211,6 +211,7 @@ struct FragileFunctionKind { DefaultArgument, PropertyInitializer, BackDeploy, + EmbeddedAlwaysEmitIntoClient, None }; diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 9608755f57f0f..0a767cf53a1b0 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -7312,7 +7312,8 @@ ERROR(usable_from_inline_attr_in_protocol,none, "an '@_alwaysEmitIntoClient' function|" \ "a default argument value|" \ "a property initializer in a '@frozen' type|" \ - "a '@backDeployed' function'}" + "a '@backDeployed' function|" \ + "an embedded function not marked '@_neverEmitIntoClient'}" ERROR(local_type_in_inlinable_function, none, "type %0 cannot be nested inside " FRAGILE_FUNC_KIND "1", diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index 86890830c50d3..56dbbe4cf5678 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -488,6 +488,11 @@ ResilienceExpansion DeclContext::getResilienceExpansion() const { case FragileFunctionKind::PropertyInitializer: case FragileFunctionKind::BackDeploy: return ResilienceExpansion::Minimal; + + /// Embedded functions are treated as fragile for diagnostics only. + /// For code gen they are treated as normal and optimized later. + case FragileFunctionKind::EmbeddedAlwaysEmitIntoClient: + case FragileFunctionKind::None: return ResilienceExpansion::Maximal; } @@ -551,6 +556,23 @@ swift::FragileFunctionKindRequest::evaluate(Evaluator &evaluator, if (AFD->getDeclContext()->isLocalContext()) continue; + // Delay checking the implicit conditions after explicit declarations. + auto checkEmbeddedAlwaysEmitIntoClient = [&](const ValueDecl *VD) { + if (!VD->getASTContext().LangOpts.hasFeature(Feature::Embedded)) + return FragileFunctionKind::None; + + bool funcIsNEIC = VD->isNeverEmittedIntoClient(); + bool storageIsNEIC = false; + if (auto accessor = dyn_cast(VD)) + storageIsNEIC = accessor->getStorage()->isNeverEmittedIntoClient(); + + // Accessors are implicitly EmbeddedAlwaysEmitIntoClient if neither the + // accessor or starage is marked @_neverEmitIntoClient. + if (!funcIsNEIC && !storageIsNEIC) + return FragileFunctionKind::EmbeddedAlwaysEmitIntoClient; + return FragileFunctionKind::None; + }; + auto funcAccess = AFD->getFormalAccessScope(/*useDC=*/nullptr, /*treatUsableFromInlineAsPublic=*/true); @@ -558,7 +580,8 @@ swift::FragileFunctionKindRequest::evaluate(Evaluator &evaluator, // If the function is not externally visible, we will not be serializing // its body. if (!funcAccess.isPublic()) { - return {FragileFunctionKind::None}; + // For non-public decls, only check embedded mode correctness. + return {checkEmbeddedAlwaysEmitIntoClient(AFD)}; } // If the function is public, @_transparent implies @inlinable. @@ -592,6 +615,10 @@ swift::FragileFunctionKindRequest::evaluate(Evaluator &evaluator, return {FragileFunctionKind::BackDeploy}; } } + + auto implicitKind = checkEmbeddedAlwaysEmitIntoClient(AFD); + if (implicitKind != FragileFunctionKind::None) + return {implicitKind}; } } diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index a4debbb322221..1cb7cd59a79c3 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -687,6 +687,9 @@ void swift::simple_display(llvm::raw_ostream &out, case FragileFunctionKind::BackDeploy: out << "backDeploy"; return; + case FragileFunctionKind::EmbeddedAlwaysEmitIntoClient: + out << "embeddedAlwaysEmitIntoClient"; + return; case FragileFunctionKind::None: out << "none"; return; diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index 780ea16a13dc6..5823e41de508a 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -5223,7 +5223,8 @@ static bool diagnoseAvailabilityCondition(PoundAvailableInfo *info, // restriction, macros would need to either be expanded when printed in // swiftinterfaces or be parsable as macros by module clients. auto fragileKind = DC->getFragileFunctionKind(); - if (fragileKind.kind != FragileFunctionKind::None) { + if (fragileKind.kind != FragileFunctionKind::None && + fragileKind.kind != FragileFunctionKind::EmbeddedAlwaysEmitIntoClient) { for (auto availSpec : info->getQueries()) { if (availSpec->getMacroLoc().isValid()) { diags.diagnose(availSpec->getMacroLoc(), diff --git a/lib/Sema/ResilienceDiagnostics.cpp b/lib/Sema/ResilienceDiagnostics.cpp index 3a4dbd1112107..4b18f10da903d 100644 --- a/lib/Sema/ResilienceDiagnostics.cpp +++ b/lib/Sema/ResilienceDiagnostics.cpp @@ -97,6 +97,14 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc, return false; } + // 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) + return false; + DowngradeToWarning downgradeToWarning = DowngradeToWarning::No; // Swift 4.2 did not perform any checks for type aliases. @@ -127,7 +135,6 @@ 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, diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index 101d711135eda..9e41ebf8fa5dd 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -2946,7 +2946,8 @@ class DeclChecker : public DeclVisitor { // We don't allow nested types inside inlinable contexts. auto kind = DC->getFragileFunctionKind(); - if (kind.kind != FragileFunctionKind::None) { + if (kind.kind != FragileFunctionKind::None && + kind.kind != FragileFunctionKind::EmbeddedAlwaysEmitIntoClient) { NTD->diagnose(diag::local_type_in_inlinable_function, NTD->getName(), kind.getSelector()); } diff --git a/test/Sema/access-level-import-embedded.swift b/test/Sema/access-level-import-embedded.swift new file mode 100644 index 0000000000000..b81ac9a7db56f --- /dev/null +++ b/test/Sema/access-level-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 19 {{struct 'StructFromDirect' imported as 'internal' from 'directs' here}} +// expected-note @-3 12 {{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' 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'}} + + 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'}} + } + + 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'}} + } + nested() + + localInternalFunc() + + explicitlyInlinable() + implicitlyInlinablePublic() + implicitlyInlinablePrivate() + 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'}} + + 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'}} + } + + 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'}} + } + 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' here; '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/implementation-only-import-embedded.swift b/test/Sema/implementation-only-import-embedded.swift new file mode 100644 index 0000000000000..831f44f946d2a --- /dev/null +++ b/test/Sema/implementation-only-import-embedded.swift @@ -0,0 +1,210 @@ +/// Test @_implementationOnly 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: -define-availability "availMacro:macOS 26.0, iOS 26.0" \ +// RUN: -enable-experimental-feature Embedded + +// REQUIRES: swift_feature_Embedded +// REQUIRES: embedded_stdlib_cross_compiling + +@_implementationOnly import directs +// expected-warning @-1 {{using '@_implementationOnly' without enabling library evolution for 'main' may lead to instability during execution}} +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()' cannot be used in a default argument value because 'directs' was imported implementation-only}} +// expected-error @-2 {{struct 'StructFromDirect' cannot be used in a default argument value because 'directs' was imported implementation-only}} +// expected-error @-3 {{struct 'StructFromDirect' cannot be used in an '@inlinable' function because 'directs' was imported implementation-only}} + _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an '@inlinable' function because 'directs' was imported implementation-only}} + // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an '@inlinable' function because 'directs' was imported implementation-only}} + + if (true) { + _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an '@inlinable' function because 'directs' was imported implementation-only}} + // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an '@inlinable' function because 'directs' was imported implementation-only}} + } + + func nested() { + _ = StructFromDirect() // expected-error {{initializer 'init()' cannot be used in an '@inlinable' function because 'directs' was imported implementation-only}} + // expected-error@-1 {{struct 'StructFromDirect' cannot be used in an '@inlinable' function because 'directs' was imported implementation-only}} + } + 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()' cannot be used in a default argument value because 'directs' was imported implementation-only}} +// expected-error @-2 {{struct 'StructFromDirect' cannot be used in a default argument value because 'directs' was imported implementation-only}} +// expected-error @-3 {{struct 'StructFromDirect' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + + _ = 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() + + if #available(availMacro, *) { } +} + +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()' cannot be used in a default argument value because 'directs' was imported implementation-only}} +// expected-error @-2 {{struct 'StructFromDirect' cannot be used in a default argument value because 'directs' was imported implementation-only}} +// expected-error @-3 {{cannot use struct 'StructFromDirect' here; 'directs' has been imported as implementation-only}} + + _ = StructFromDirect() + + if (true) { + _ = StructFromDirect() + } + + func nested() { + _ = StructFromDirect() + } + nested() + + localInternalFunc() + + explicitlyInlinable() + implicitlyInlinablePublic() + implicitlyInlinablePrivate() + explicitNonInliable() +} + +@_neverEmitIntoClient +internal func explicitNonInliableInternal(arg: StructFromDirect = StructFromDirect()) { + _ = StructFromDirect() + + if (true) { + _ = StructFromDirect() + } + + func nested() { + _ = StructFromDirect() + } + nested() + + localInternalFunc() + + explicitlyInlinable() + implicitlyInlinablePublic() + implicitlyInlinablePrivate() + explicitNonInliable() + + struct NestedStruct {} +} + +struct Accessors { + public var var1: Int { + get { + globalFunctionFromDirect() // expected-error {{global function 'globalFunctionFromDirect()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + return 0 + } + } + + @_alwaysEmitIntoClient + public var var2: Int { + get { + globalFunctionFromDirect() // expected-error {{global function 'globalFunctionFromDirect()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' was imported implementation-only}} + return 0 + } + } + + @_neverEmitIntoClient + public var var3: Int { + get { + globalFunctionFromDirect() + return 0 + } + } + + public var var4: Int { + @_neverEmitIntoClient + get { + globalFunctionFromDirect() + return 0 + } + } +} + +public func legalAccessToIndirect(arg: StructFromIndirect = StructFromIndirect()) { + _ = StructFromIndirect() + + if (true) { + _ = StructFromIndirect() + } + + func nested() { + _ = StructFromIndirect() + } + nested() +} + +public struct ExposedLayoutPublic { + public var publicField: StructFromDirect // expected-error {{cannot use struct 'StructFromDirect' here; 'directs' has been imported as implementation-only}} + + private var privateField: StructFromDirect // FIXME should error +} + +private struct ExposedLayoutPrivate { + private var privateField: StructFromDirect // FIXME should error +} diff --git a/test/embedded/implementation-only-import-build.swift b/test/embedded/implementation-only-import-build.swift new file mode 100644 index 0000000000000..82b0b276deb03 --- /dev/null +++ b/test/embedded/implementation-only-import-build.swift @@ -0,0 +1,66 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -o %t/indirects.swiftmodule \ +// RUN: %S/../Sema/Inputs/implementation-only-imports/indirects.swift \ +// RUN: -enable-experimental-feature Embedded +// RUN: %target-swift-frontend -emit-module -o %t/directs.swiftmodule -I %t\ +// RUN: %S/../Sema/Inputs/implementation-only-imports/directs.swift \ +// RUN: -enable-experimental-feature Embedded + +// RUN: %target-swift-frontend -emit-sil %s -I %t \ +// RUN: -enable-experimental-feature Embedded + +// REQUIRES: swift_feature_Embedded +// REQUIRES: embedded_stdlib_cross_compiling + +@_implementationOnly import directs +import indirects + +internal func localInternalFunc() {} + +public func implicitlyInlinablePublic() { + localInternalFunc() +} + +private func implicitlyInlinablePrivate() { + localInternalFunc() +} + +@_neverEmitIntoClient +public func explicitNonInliable() { + _ = StructFromDirect() + + if (true) { + _ = StructFromDirect() + } + + @_neverEmitIntoClient + func nested() { + _ = StructFromDirect() + } + nested() + + localInternalFunc() +} + +@_alwaysEmitIntoClient +public func legalAccessToIndirect() { + _ = StructFromIndirect() + + if (true) { + _ = StructFromIndirect() + } + + func nested() { + _ = StructFromIndirect() + } + nested() +} + +extension Array { + @_alwaysEmitIntoClient + public var myMutableSpan: Int { + get { + return 0 + } + } +} diff --git a/test/embedded/linkage/implementation_only_hiding.swift b/test/embedded/linkage/implementation_only_hiding.swift index 079c6f02cc7ca..a987f75925594 100644 --- a/test/embedded/linkage/implementation_only_hiding.swift +++ b/test/embedded/linkage/implementation_only_hiding.swift @@ -12,7 +12,7 @@ // RUN: cp %S/Inputs/CHeader.h %t/Dependencies/ // RUN: cp %S/Inputs/module.modulemap %t/Dependencies/ -// RUN: split-file %s %t/Files +// RUN: split-file %s %t/Files --leading-lines // Compile the Swift dependencies into that same location. // RUN: %target-swift-frontend -parse-as-library -emit-module %t/Dependencies/SwiftDependency.swift -enable-experimental-feature Embedded -o %t/Dependencies/SwiftDependency.swiftmodule @@ -21,6 +21,9 @@ // against the dependencies. // RUN: %target-swift-frontend -parse-as-library -emit-module %t/Files/Library.swift -enable-experimental-feature Embedded -I %t/Dependencies/ -o %t/Modules/Library.swiftmodule +// Building the library with invalid uses trigger errors. +// RUN: %target-swift-frontend -parse-as-library -typecheck -verify %t/Files/Library.swift -enable-experimental-feature Embedded -I %t/Dependencies/ -o %t/Modules/Library.swiftmodule -DBAD_IOI_USAGE + // Remove the dependencies so there is no way we can find them later. // RUN: rm -rf %t/Dependencies @@ -28,19 +31,12 @@ // @_neverEmitIntoClient hides the body of test(). // RUN: %target-swift-frontend -emit-ir -parse-as-library %t/Files/Application.swift -enable-experimental-feature Embedded -I %t/Modules -o %t/Application.ir -// Build the application against the library, but intentionally trigger -// deserialization of some serialized SIL that refers to an implementation-only -// dependency. Right now, these fail spectacularly. Over time, we want them to -// become compile-time errors or start working. -// RUN: not --crash %target-swift-frontend -emit-ir -parse-as-library %t/Files/Application.swift -enable-experimental-feature Embedded -I %t/Modules -o %t/Application.ir -DBAD_C_USAGE -// RUN: not --crash %target-swift-frontend -emit-ir -parse-as-library %t/Files/Application.swift -enable-experimental-feature Embedded -I %t/Modules -o %t/Application.ir -DBAD_SWIFT_USAGE - // REQUIRES: swift_in_compiler // REQUIRES: swift_feature_Embedded //--- Library.swift -@_implementationOnly import CDependency -@_implementationOnly import SwiftDependency +@_implementationOnly import CDependency // expected-warning {{using '@_implementationOnly' without enabling library evolution for 'Library' may lead to instability during execution}} +@_implementationOnly import SwiftDependency // expected-warning {{using '@_implementationOnly' without enabling library evolution for 'Library' may lead to instability during execution}} @_neverEmitIntoClient public func test() { @@ -48,13 +44,17 @@ public func test() { A().doSomething() } +#if BAD_IOI_USAGE public func badCLibraryUsage() { - _ = getPoint(3.14159, 2.71828) + _ = getPoint(3.14159, 2.71828) // expected-error {{global function 'getPoint' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'CDependency' was imported implementation-only}} } public func badSwiftLibraryUsage() { - A().doSomething() + A().doSomething() // expected-error {{struct 'A' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'SwiftDependency' was imported implementation-only}} + // expected-error @-1 {{initializer 'init()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'SwiftDependency' was imported implementation-only}} + // expected-error @-2 {{instance method 'doSomething()' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'SwiftDependency' was imported implementation-only}} } +#endif //--- Application.swift @@ -62,12 +62,4 @@ import Library public func useTest() { test() - -#if BAD_C_USAGE - badCLibraryUsage() -#endif - -#if BAD_SWIFT_USAGE - badSwiftLibraryUsage() -#endif }