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
5 changes: 2 additions & 3 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1121,9 +1121,8 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl>, public Swi
getBackDeployedAttrAndRange(ASTContext &Ctx,
bool forTargetVariant = false) const;

/// Returns true if the decl has an active `@backDeployed` attribute for the
/// given context.
bool isBackDeployed(ASTContext &Ctx) const;
/// Returns true if the decl has a valid and active `@backDeployed` attribute.
bool isBackDeployed() const;

/// Returns the starting location of the entire declaration.
SourceLoc getStartLoc() const { return getSourceRange().Start; }
Expand Down
9 changes: 8 additions & 1 deletion lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3075,7 +3075,14 @@ void ValueDecl::dumpRef(raw_ostream &os) const {
printContext(os, getDeclContext());
os << ".";
// Print name.
getName().printPretty(os);
if (auto accessor = dyn_cast<AccessorDecl>(this)) {
// If it's an accessor, print the name of the storage and then the
// accessor kind.
accessor->getStorage()->getName().printPretty(os);
os << "." << Decl::getDescriptiveKindName(accessor->getDescriptiveKind());
} else {
getName().printPretty(os);
}
} else {
auto moduleName = cast<ModuleDecl>(this)->getRealName();
os << moduleName;
Expand Down
17 changes: 16 additions & 1 deletion lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,22 @@ Decl::getBackDeployedAttrAndRange(ASTContext &Ctx,
return std::nullopt;
}

bool Decl::isBackDeployed(ASTContext &Ctx) const {
bool Decl::isBackDeployed() const {
auto &Ctx = getASTContext();

// A function declared in a local context can never be back-deployed.
if (getDeclContext()->isLocalContext())
return false;

// A non-public function can never be back-deployed.
if (auto VD = dyn_cast<ValueDecl>(this)) {
auto access =
VD->getFormalAccessScope(/*useDC=*/nullptr,
/*treatUsableFromInlineAsPublic=*/true);
if (!access.isPublic())
return false;
}

if (getBackDeployedAttrAndRange(Ctx))
return true;

Expand Down
4 changes: 2 additions & 2 deletions lib/AST/DeclContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ swift::FragileFunctionKindRequest::evaluate(Evaluator &evaluator,
return {FragileFunctionKind::AlwaysEmitIntoClient};
}

if (AFD->isBackDeployed(context->getASTContext())) {
if (AFD->isBackDeployed()) {
return {FragileFunctionKind::BackDeploy};
}

Expand All @@ -576,7 +576,7 @@ swift::FragileFunctionKindRequest::evaluate(Evaluator &evaluator,
if (storage->getAttrs().hasAttribute<AlwaysEmitIntoClientAttr>()) {
return {FragileFunctionKind::AlwaysEmitIntoClient};
}
if (storage->isBackDeployed(context->getASTContext())) {
if (storage->isBackDeployed()) {
return {FragileFunctionKind::BackDeploy};
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/SIL/IR/SILDeclRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1084,7 +1084,7 @@ bool SILDeclRef::isBackDeployed() const {
&& "should not get backDeployed from ABI-only decl");

if (auto afd = dyn_cast<AbstractFunctionDecl>(decl))
return afd->isBackDeployed(getASTContext());
return afd->isBackDeployed();

return false;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/SILGen/SILGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1527,7 +1527,7 @@ void SILGenModule::emitAbstractFuncDecl(AbstractFunctionDecl *AFD) {

emitDistributedThunkForDecl(AFD);

if (AFD->isBackDeployed(M.getASTContext())) {
if (AFD->isBackDeployed()) {
// Emit the fallback function that will be used when the original function
// is unavailable at runtime.
auto fallback = SILDeclRef(AFD).asBackDeploymentKind(
Expand Down
26 changes: 25 additions & 1 deletion test/Inputs/lazy_typecheck.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public func publicFuncWithOpaqueReturnType() -> some PublicProto {

@available(SwiftStdlib 5.1, *)
@_alwaysEmitIntoClient public func publicAEICFuncWithOpaqueReturnType() -> some Any {
if #available(macOS 20, *) {
if #available(macOS 99, *) {
return 3
} else {
return "hi"
Expand Down Expand Up @@ -109,6 +109,30 @@ var internalGlobalVar: NoTypecheck = NoTypecheck()
var internalGlobalVarInferredType = NoTypecheck()
var internalGlobalTypealiasVar: PublicIntAlias = NoTypecheck.int

@backDeployed(before: macOS 99, iOS 99, tvOS 99, watchOS 99, visionOS 99)
public private(set) var publicGlobalVarBackDeployedWithPrivateSetter: Int {
get { 0 }
set { // Implicitly not @backDeployed.
_ = NoTypecheck()
}
}

@backDeployed(before: macOS 99, iOS 99, tvOS 99, watchOS 99, visionOS 99)
public internal(set) var publicGlobalVarBackDeployedWithInternalSetter: Int {
get { 0 }
set { // Implicitly not @backDeployed.
_ = NoTypecheck()
}
}

@backDeployed(before: macOS 99, iOS 99, tvOS 99, watchOS 99, visionOS 99)
public package(set) var publicGlobalVarBackDeployedWithPackageSetter: Int {
get { 0 }
set { // Implicitly not @backDeployed.
_ = NoTypecheck()
}
}

// MARK: - Nominal types

public protocol EmptyPublicProto {}
Expand Down
47 changes: 46 additions & 1 deletion test/attr/attr_backDeployed.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ public struct TopLevelStruct {
set(newValue) {}
}

@backDeployed(before: macOS 12.0)
public private(set) var readWritePropertyPrivateSet: Int {
get { 42 }
set(newValue) {}
}

@backDeployed(before: macOS 12.0)
public internal(set) var readWritePropertyInternalSet: Int {
get { 42 }
set(newValue) {}
}

@backDeployed(before: macOS 12.0)
public subscript(at index: Int) -> Int {
get { 42 }
Expand Down Expand Up @@ -234,7 +246,6 @@ public final class CannotBackDeployClassDeinit {
deinit {}
}

// Ok, final decls in a non-final, derived class
public class CannotBackDeployOverride: TopLevelClass {
@backDeployed(before: macOS 12.0) // expected-error {{'@backDeployed' cannot be combined with 'override'}}
final public override func hook() {}
Expand Down Expand Up @@ -293,6 +304,40 @@ public func cannotBackDeployFuncWithOpaqueResultType() -> some TopLevelProtocol
return ConformsToTopLevelProtocol()
}

public struct CannotBackDeployNonPublicAccessors {
private var privateVar: Int {
@backDeployed(before: macOS 12.0) // expected-error {{'@backDeployed' may not be used on private declarations}}
get { 0 }

@backDeployed(before: macOS 12.0) // expected-error {{'@backDeployed' may not be used on private declarations}}
set { }
}

internal var internalVar: Int {
@backDeployed(before: macOS 12.0) // expected-error {{'@backDeployed' may not be used on internal declarations}}
get { 0 }

@backDeployed(before: macOS 12.0) // expected-error {{'@backDeployed' may not be used on internal declarations}}
set { }
}

public private(set) var publicVarPrivateSet: Int {
@backDeployed(before: macOS 12.0)
get { 0 }

@backDeployed(before: macOS 12.0) // expected-error {{'@backDeployed' may not be used on private declarations}}
set { }
}

public internal(set) var publicVarInternalSet: Int {
@backDeployed(before: macOS 12.0)
get { 0 }

@backDeployed(before: macOS 12.0) // expected-error {{'@backDeployed' may not be used on internal declarations}}
set { }
}
}

// MARK: - Function body diagnostics

public struct FunctionBodyDiagnostics {
Expand Down