Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1068,6 +1068,14 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl>, 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<void(Decl *)>;

/// Iterate over the auxiliary declarations for this declaration,
Expand Down
6 changes: 5 additions & 1 deletion include/swift/AST/DeclAttr.def
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5011,6 +5011,7 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, Label>,
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)
Expand Down
4 changes: 4 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2281,6 +2281,10 @@ bool Decl::isObjCImplementation() const {
return getAttrs().hasAttribute<ObjCImplementationAttr>(/*AllowInvalid=*/true);
}

bool Decl::isNeverEmittedIntoClient() const {
return getAttrs().hasAttribute<NeverEmitIntoClientAttr>();
}

PatternBindingDecl::PatternBindingDecl(SourceLoc StaticLoc,
StaticSpellingKind StaticSpelling,
SourceLoc VarLoc,
Expand Down
1 change: 1 addition & 0 deletions lib/ASTGen/Sources/ASTGen/DeclAttrs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ extension ASTGenVisitor {
.MainType,
.Marker,
.MoveOnly,
.NeverEmitIntoClient,
.NoAllocation,
.NoDerivative,
.NoEagerMove,
Expand Down
10 changes: 10 additions & 0 deletions lib/SIL/IR/SILDeclRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() &&
Expand Down Expand Up @@ -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();
Expand Down
1 change: 1 addition & 0 deletions lib/Sema/TypeCheckAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {

#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)
Expand Down
1 change: 1 addition & 0 deletions lib/Sema/TypeCheckDeclOverride.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions lib/Serialization/SerializeSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
81 changes: 81 additions & 0 deletions test/embedded/linkage/never_emit_into_client.swift
Original file line number Diff line number Diff line change
@@ -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<Int> {

//--- 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<Int>{{$}}
// 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<Int> {
// 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"