Skip to content

Commit 0f890b8

Browse files
committed
Sema: Diagnose use of the @_backDeploy attribute on non-final and @objc decls.
1 parent 7b9b9b8 commit 0f890b8

File tree

4 files changed

+114
-18
lines changed

4 files changed

+114
-18
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3161,6 +3161,10 @@ ERROR(final_not_allowed_here,none,
31613161
"'final' may only be applied to classes, properties, methods, and "
31623162
"subscripts", ())
31633163

3164+
ERROR(attr_incompatible_with_non_final,none,
3165+
"'%0' cannot be applied to a non-final %1",
3166+
(DeclAttribute, DescriptiveDeclKind))
3167+
31643168
ERROR(final_not_on_accessors,none,
31653169
"'final' cannot be applied to accessors, it must be put on the "
31663170
"%select{var|let|subscript}0", (unsigned))
@@ -6291,7 +6295,8 @@ ERROR(cannot_convert_default_value_type_to_argument_type, none,
62916295
//------------------------------------------------------------------------------
62926296

62936297
ERROR(attr_incompatible_with_back_deploy,none,
6294-
"'%0' cannot be applied to back deployed declarations", (DeclAttribute))
6298+
"'%0' cannot be applied to a back deployed %1",
6299+
(DeclAttribute, DescriptiveDeclKind))
62956300

62966301
#define UNDEFINE_DIAGNOSTIC_MACROS
62976302
#include "DefineDiagnosticMacros.h"

lib/SILGen/SILGenApply.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,10 +1030,8 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
10301030
}
10311031

10321032
void processClassMethod(DeclRefExpr *e, AbstractFunctionDecl *afd) {
1033-
// FIXME(backDeploy): Investigate support for back deployed class method
1034-
// calls
10351033
assert(!afd->isBackDeployed() &&
1036-
"back deployed method calls are unsupported");
1034+
"cannot back deploy dynamically dispatched methods");
10371035

10381036
ArgumentSource selfArgSource(selfApply->getBase());
10391037
setSelfParam(std::move(selfArgSource));

lib/Sema/TypeCheckAttr.cpp

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
8080
attr,
8181
isError ? diag::attr_not_on_decl_with_invalid_access_level
8282
: diag::attr_has_no_effect_on_decl_with_access_level,
83-
attr, VD->getFormalAccess());
83+
attr, access.accessLevelForDiagnostics());
8484
return true;
8585
}
8686
}
@@ -3508,28 +3508,46 @@ void AttributeChecker::checkBackDeployAttrs(ArrayRef<BackDeployAttr *> Attrs) {
35083508
// ABI version of the declaration when it is available.
35093509
if (auto *AEICA = D->getAttrs().getAttribute<AlwaysEmitIntoClientAttr>()) {
35103510
diagnoseAndRemoveAttr(AEICA, diag::attr_incompatible_with_back_deploy,
3511-
AEICA);
3511+
AEICA, D->getDescriptiveKind());
35123512
}
35133513

35143514
if (auto *IA = D->getAttrs().getAttribute<InlinableAttr>()) {
3515-
diagnoseAndRemoveAttr(IA, diag::attr_incompatible_with_back_deploy, IA);
3515+
diagnoseAndRemoveAttr(IA, diag::attr_incompatible_with_back_deploy, IA,
3516+
D->getDescriptiveKind());
35163517
}
35173518

35183519
if (auto *TA = D->getAttrs().getAttribute<TransparentAttr>()) {
3519-
diagnoseAndRemoveAttr(TA, diag::attr_incompatible_with_back_deploy, TA);
3520+
diagnoseAndRemoveAttr(TA, diag::attr_incompatible_with_back_deploy, TA,
3521+
D->getDescriptiveKind());
35203522
}
35213523

3524+
// @objc conflicts with back deployment since it implies dynamic dispatch.
3525+
if (auto *OA = D->getAttrs().getAttribute<ObjCAttr>()) {
3526+
diagnose(OA->getLocation(), diag::attr_incompatible_with_back_deploy, OA,
3527+
D->getDescriptiveKind());
3528+
}
3529+
3530+
// Only functions, methods, computed properties, and subscripts are
3531+
// back-deployable, so D should be ValueDecl.
3532+
auto *VD = cast<ValueDecl>(D);
35223533
std::map<PlatformKind, SourceLoc> seenPlatforms;
35233534

35243535
for (auto *Attr : Attrs) {
35253536
// Back deployment only makes sense for public declarations.
35263537
if (diagnoseAndRemoveAttrIfDeclIsNonPublic(Attr, /*isError=*/true))
35273538
continue;
35283539

3529-
if (auto *VD = dyn_cast<VarDecl>(D)) {
3540+
// Back deployment isn't compatible with dynamic dispatch.
3541+
if (VD->isPotentiallyOverridable() && !VD->isFinal()) {
3542+
diagnose(Attr->getLocation(), diag::attr_incompatible_with_non_final,
3543+
Attr, D->getDescriptiveKind());
3544+
continue;
3545+
}
3546+
3547+
if (auto *VarD = dyn_cast<VarDecl>(D)) {
35303548
// There must be a function body to back deploy so for vars we require
35313549
// that they be computed in order to allow back deployment.
3532-
if (VD->hasStorageOrWrapsStorage()) {
3550+
if (VarD->hasStorageOrWrapsStorage()) {
35333551
diagnoseAndRemoveAttr(Attr, diag::attr_not_on_stored_properties, Attr);
35343552
continue;
35353553
}
@@ -3556,9 +3574,6 @@ void AttributeChecker::checkBackDeployAttrs(ArrayRef<BackDeployAttr *> Attrs) {
35563574
// fallback could never be executed at runtime.
35573575
auto IntroVer = D->getIntroducedOSVersion(Platform);
35583576
if (Attr->Version <= IntroVer.getValue()) {
3559-
// Only functions, methods, computed properties, and subscripts are
3560-
// back-deployable.
3561-
auto *VD = cast<ValueDecl>(D);
35623577
diagnose(AtLoc, diag::attr_has_no_effect_decl_not_available_before, Attr,
35633578
VD->getName(), prettyPlatformString(Platform), Attr->Version);
35643579
continue;

test/attr/attr_backDeploy.swift

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,76 @@ public struct TopLevelStruct {
2424
public var backDeployedComputedProperty: Int { 98 }
2525
}
2626

27+
// OK: final function decls in a non-final class
2728
public class TopLevelClass {
2829
@available(macOS 11.0, *)
2930
@_backDeploy(macOS 12.0)
3031
final public func backDeployedFinalMethod() {}
3132

33+
@available(macOS 11.0, *)
34+
@_backDeploy(macOS 12.0)
35+
final public var backDeployedFinalComputedProperty: Int { 98 }
36+
37+
@available(macOS 11.0, *)
38+
@_backDeploy(macOS 12.0)
39+
public static func backDeployedStaticMethod() {}
40+
41+
@available(macOS 11.0, *)
42+
@_backDeploy(macOS 12.0)
43+
public final class func backDeployedClassMethod() {}
44+
}
45+
46+
// OK: function decls in a final class
47+
final public class FinalTopLevelClass {
48+
@available(macOS 11.0, *)
49+
@_backDeploy(macOS 12.0)
50+
public func backDeployedMethod() {}
51+
3252
@available(macOS 11.0, *)
3353
@_backDeploy(macOS 12.0)
3454
public var backDeployedComputedProperty: Int { 98 }
3555
}
3656

57+
// OK: final function decls on an actor
58+
@available(macOS 11.0, *)
59+
public actor TopLevelActor {
60+
@available(macOS 11.0, *)
61+
@_backDeploy(macOS 12.0)
62+
final public func finalActorMethod() {}
63+
64+
// OK: actor methods are effectively final
65+
@available(macOS 11.0, *)
66+
@_backDeploy(macOS 12.0)
67+
public func actorMethod() {}
68+
}
69+
70+
// OK: function decls in extension on public types
71+
extension TopLevelStruct {
72+
@available(macOS 11.0, *)
73+
@_backDeploy(macOS 12.0)
74+
public func backDeployedExtensionMethod() {}
75+
}
76+
77+
extension TopLevelClass {
78+
@available(macOS 11.0, *)
79+
@_backDeploy(macOS 12.0)
80+
final public func backDeployedExtensionMethod() {}
81+
}
82+
83+
extension FinalTopLevelClass {
84+
@available(macOS 11.0, *)
85+
@_backDeploy(macOS 12.0)
86+
public func backDeployedExtensionMethod() {}
87+
}
88+
89+
public protocol TopLevelProtocol {}
90+
91+
extension TopLevelProtocol {
92+
@available(macOS 11.0, *)
93+
@_backDeploy(macOS 12.0)
94+
public func backDeployedExtensionMethod() {}
95+
}
96+
3797
// MARK: - Unsupported declaration types
3898

3999
@_backDeploy(macOS 12.0) // expected-error {{'@_backDeploy' attribute cannot be applied to this declaration}}
@@ -60,6 +120,13 @@ public var cannotBackDeployTopLevelVar = 79
60120
@_backDeploy(macOS 12.0) // expected-error {{'@_backDeploy' attribute cannot be applied to this declaration}}
61121
extension TopLevelStruct {}
62122

123+
@_backDeploy(macOS 12.0) // expected-error {{'@_backDeploy' attribute cannot be applied to this declaration}}
124+
protocol CannotBackDeployProtocol {}
125+
126+
@available(macOS 11.0, *)
127+
@_backDeploy(macOS 12.0) // expected-error {{'@_backDeploy' attribute cannot be applied to this declaration}}
128+
public actor CannotBackDeployActor {}
129+
63130
// MARK: - Incompatible declarations
64131

65132
@_backDeploy(macOS 12.0) // expected-error {{'@_backDeploy' may not be used on fileprivate declarations}}
@@ -71,11 +138,22 @@ private func privateFunc() {}
71138
@_backDeploy(macOS 12.0) // expected-error {{'@_backDeploy' may not be used on internal declarations}}
72139
internal func internalFunc() {}
73140

74-
// FIXME(backDeploy): back deployed methods must be final
141+
private struct PrivateTopLevelStruct {
142+
@_backDeploy(macOS 12.0) // expected-error {{'@_backDeploy' may not be used on private declarations}}
143+
public func effectivelyPrivateFunc() {}
144+
}
145+
75146
public class TopLevelClass2 {
147+
@_backDeploy(macOS 12.0) // expected-error {{'@_backDeploy' cannot be applied to a non-final instance method}}
148+
public func nonFinalMethod() {}
149+
76150
@available(macOS 11.0, *)
77151
@_backDeploy(macOS 12.0)
78-
public func backDeployedNonFinalMethod() {}
152+
@objc // expected-error {{'@objc' cannot be applied to a back deployed instance method}}
153+
final public func objcMethod() {}
154+
155+
@_backDeploy(macOS 12.0) // expected-error {{'@_backDeploy' cannot be applied to a non-final class method}}
156+
public class func nonFinalClassMethod() {}
79157
}
80158

81159
@_backDeploy(macOS 12.0) // expected-error {{'@_backDeploy' requires that 'missingAllAvailabilityFunc()' have explicit availability for macOS}}
@@ -104,17 +182,17 @@ public func duplicatePlatformsFunc2() {}
104182

105183
@available(macOS 11.0, *)
106184
@_backDeploy(macOS 12.0)
107-
@_alwaysEmitIntoClient // expected-error {{'@_alwaysEmitIntoClient' cannot be applied to back deployed declarations}}
185+
@_alwaysEmitIntoClient // expected-error {{'@_alwaysEmitIntoClient' cannot be applied to a back deployed global function}}
108186
public func alwaysEmitIntoClientFunc() {}
109187

110188
@available(macOS 11.0, *)
111189
@_backDeploy(macOS 12.0)
112-
@inlinable // expected-error {{'@inlinable' cannot be applied to back deployed declarations}}
190+
@inlinable // expected-error {{'@inlinable' cannot be applied to a back deployed global function}}
113191
public func inlinableFunc() {}
114192

115193
@available(macOS 11.0, *)
116194
@_backDeploy(macOS 12.0)
117-
@_transparent // expected-error {{'@_transparent' cannot be applied to back deployed declarations}}
195+
@_transparent // expected-error {{'@_transparent' cannot be applied to a back deployed global function}}
118196
public func transparentFunc() {}
119197

120198
// MARK: - Attribute parsing

0 commit comments

Comments
 (0)