diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index a04531ea24313..72c33ec384335 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -1068,6 +1068,14 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated, public Swi /// behaviors for it and, if it's an extension, its members. bool isObjCImplementation() const; + /// True if this declaration should never have its implementation made + /// available to any client. This overrides cross-module optimization and + /// optimizations that might use the implementation, such that the only + /// implementation of this function is the one compiled into its owning + /// module. Practically speaking, this prohibits serialization of the SIL + /// for this definition. + bool isNeverEmittedIntoClient() const; + using AuxiliaryDeclCallback = llvm::function_ref; /// Iterate over the auxiliary declarations for this declaration, diff --git a/include/swift/AST/DeclAttr.def b/include/swift/AST/DeclAttr.def index 51ed6e7808f39..8da6f1541ac01 100644 --- a/include/swift/AST/DeclAttr.def +++ b/include/swift/AST/DeclAttr.def @@ -201,7 +201,11 @@ SIMPLE_DECL_ATTR(requires_stored_property_inits, RequiresStoredPropertyInits, ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | UnreachableInABIAttr, 27) -// Unused '28' +SIMPLE_DECL_ATTR(_neverEmitIntoClient, NeverEmitIntoClient, + OnVar | OnSubscript | OnAbstractFunction, + UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr, + 28) + // Unused '29' SIMPLE_DECL_ATTR(nonobjc, NonObjC, diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 872793e4c1701..1f4dd877bb151 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -5011,6 +5011,7 @@ class PrintAttribute : public AttributeVisitor, TRIVIAL_ATTR_PRINTER(NSApplicationMain, ns_application_main) TRIVIAL_ATTR_PRINTER(NSCopying, ns_copying) TRIVIAL_ATTR_PRINTER(NSManaged, ns_managed) + TRIVIAL_ATTR_PRINTER(NeverEmitIntoClient, never_emit_into_client) TRIVIAL_ATTR_PRINTER(NoAllocation, no_allocation) TRIVIAL_ATTR_PRINTER(NoDerivative, no_derivative) TRIVIAL_ATTR_PRINTER(NoEagerMove, no_eager_move) diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index eaa4855c63abf..2443ff45ae05e 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2281,6 +2281,10 @@ bool Decl::isObjCImplementation() const { return getAttrs().hasAttribute(/*AllowInvalid=*/true); } +bool Decl::isNeverEmittedIntoClient() const { + return getAttrs().hasAttribute(); +} + PatternBindingDecl::PatternBindingDecl(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, SourceLoc VarLoc, diff --git a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift index 0d7f49b4d03ef..f6a5a96aed226 100644 --- a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift +++ b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift @@ -267,6 +267,7 @@ extension ASTGenVisitor { .MainType, .Marker, .MoveOnly, + .NeverEmitIntoClient, .NoAllocation, .NoDerivative, .NoEagerMove, diff --git a/lib/SIL/IR/SILDeclRef.cpp b/lib/SIL/IR/SILDeclRef.cpp index 921f95ae726cf..5a4b131627d2e 100644 --- a/lib/SIL/IR/SILDeclRef.cpp +++ b/lib/SIL/IR/SILDeclRef.cpp @@ -887,6 +887,11 @@ SerializedKind_t SILDeclRef::getSerializedKind() const { ASSERT(ABIRoleInfo(d).providesAPI() && "should not get serialization info from ABI-only decl"); + // A declaration marked as "never emitted into client" will not have its SIL + // serialized, ever. + if (d->isNeverEmittedIntoClient()) + return IsNotSerialized; + // Default and property wrapper argument generators are serialized if the // containing declaration is public. if (isDefaultArgGenerator() || (isPropertyWrapperBackingInitializer() && @@ -1102,6 +1107,11 @@ bool SILDeclRef::declHasNonUniqueDefinition(const ValueDecl *decl) { if (!decl->getASTContext().LangOpts.hasFeature(Feature::Embedded)) return false; + // If the declaration is marked as @_neverEmitIntoClient, it has a unique + // definition. + if (decl->isNeverEmittedIntoClient()) + return false; + // If the declaration is not from the main module, treat its definition as // non-unique. auto module = decl->getModuleContext(); diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 9e9d65bc8a694..749f8d7899901 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -153,6 +153,7 @@ class AttributeChecker : public AttributeVisitor { #define IGNORED_ATTR(X) void visit##X##Attr(X##Attr *) {} IGNORED_ATTR(AlwaysEmitIntoClient) + IGNORED_ATTR(NeverEmitIntoClient) IGNORED_ATTR(HasInitialValue) IGNORED_ATTR(ClangImporterSynthesizedType) IGNORED_ATTR(Convenience) diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index fa620318394e9..104bd0beeac61 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -1589,6 +1589,7 @@ namespace { UNINTERESTING_ATTR(AccessControl) UNINTERESTING_ATTR(Alignment) UNINTERESTING_ATTR(AlwaysEmitIntoClient) + UNINTERESTING_ATTR(NeverEmitIntoClient) UNINTERESTING_ATTR(Borrowed) UNINTERESTING_ATTR(Borrowing) UNINTERESTING_ATTR(CDecl) diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index 2bc2d2b2f6903..49254e5106554 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -3575,6 +3575,12 @@ bool SILSerializer::shouldEmitFunctionBody(const SILFunction *F, if (F->isAvailableExternally()) return false; + if (F->getDeclRef().hasDecl()) { + if (auto decl = F->getDeclRef().getDecl()) + if (decl->isNeverEmittedIntoClient()) + return false; + } + // If we are asked to serialize everything, go ahead and do it. if (ShouldSerializeAll) return true; diff --git a/test/embedded/linkage/never_emit_into_client.swift b/test/embedded/linkage/never_emit_into_client.swift new file mode 100644 index 0000000000000..83bdf8f5ce388 --- /dev/null +++ b/test/embedded/linkage/never_emit_into_client.swift @@ -0,0 +1,81 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +// Library module + +// SIL checking +// RUN: %target-swift-frontend %t/Library.swift -parse-as-library -entry-point-function-name Library_main -enable-experimental-feature Embedded -emit-sil -emit-module-path %t/Modules/Library.swiftmodule -o - | %FileCheck -check-prefix LIBRARY-SIL %s + +// IR checking to ensure we get the right weak symbols. +// RUN: %target-swift-frontend %t/Library.swift -parse-as-library -entry-point-function-name Library_main -enable-experimental-feature Embedded -emit-ir -o - | %FileCheck -check-prefix LIBRARY-IR --dump-input-filter all %s + +// Application module + +// RUN: %target-swift-frontend %t/Application.swift -I %t/Modules -parse-as-library -entry-point-function-name Application_main -enable-experimental-feature Embedded -emit-sil -o - | %FileCheck -check-prefix APPLICATION-SIL %s + +// RUN: %target-swift-frontend %t/Application.swift -I %t/Modules -parse-as-library -entry-point-function-name Application_main -enable-experimental-feature Embedded -emit-ir -o - | %FileCheck -check-prefix APPLICATION-IR %s + +// REQUIRES: swift_in_compiler +// REQUIRES: swift_feature_Embedded + +//--- Library.swift + +// LIBRARY-IR: define {{(protected |dllexport )?}}swiftcc ptr @"$e7Library5helloSaySiGyF"() +@_neverEmitIntoClient +public func hello() -> [Int] { + getArray() +} + +// LIBRARY-IR: define {{(protected |dllexport )?}}swiftcc ptr @"$e7Library8getArraySaySiGyF"() +public func getArray() -> [Int] { + throughInternal() +} + +// LIBRARY-IR: define {{(protected |dllexport )?}}swiftcc ptr @"$e7Library15throughInternalSaySiGyF"() +func throughInternal() -> [Int] { + throughPrivate() +} + +// LIBRARY-IR: define {{(protected |dllexport )?}}swiftcc ptr @"$e7Library14throughPrivate +private func throughPrivate() -> [Int] { + [5, 6, 7] +} + +// LIBRARY-IR-NOT: unnecessary +public func unnecessary() -> Int { 5 } + +// LIBRARY-IR: define linkonce_odr hidden swiftcc { ptr, ptr } @"$es27_allocateUninitializedArrayySayxG_BptBwlFSi_Tg5" + +// LIBRARY-SIL: sil @$e7Library5helloSaySiGyF +// LIBRARY-SIL: sil @$e7Library8getArraySaySiGyF : $@convention(thin) () -> @owned Array { + +//--- Application.swift +import Library + +@_neverEmitIntoClient +public func testMe() { + _ = hello() + _ = getArray() +} + +// Note: "hello" is emitted only into the object file, so there is no definition +// here. + +// APPLICATION-SIL: sil @$e7Library5helloSaySiGyF : $@convention(thin) () -> @owned Array{{$}} +// APPLICATION-IR: declare swiftcc ptr @"$e7Library5helloSaySiGyF"() + +// Note: "getArray" is not @_neverEmitIntoClient, so it's definition is +// available. + +// APPLICATION-SIL: sil public_external @$e7Library8getArraySaySiGyF : $@convention(thin) () -> @owned Array { +// APPLICATION-IR: define linkonce_odr hidden swiftcc ptr @"$e7Library8getArraySaySiGyF"() + +// APPLICATION-IR: define{{.*}}@Application_main +@main +struct Main { + static func main() { + } +} + +// APPLICATION-IR: define linkonce_odr hidden swiftcc { ptr, ptr } @"$es27_allocateUninitializedArrayySayxG_BptBwlFSi_Tg5" +