Skip to content

Commit 5a648ed

Browse files
authored
Merge pull request #24997 from xymus/extension-availability
Support unavailable and obsoleted attributes on extensions
2 parents 87b51fc + 9b59ec5 commit 5a648ed

File tree

5 files changed

+89
-8
lines changed

5 files changed

+89
-8
lines changed

lib/AST/Attr.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1048,7 +1048,14 @@ AvailableVersionComparison AvailableAttr::getVersionAvailability(
10481048

10491049
const AvailableAttr *AvailableAttr::isUnavailable(const Decl *D) {
10501050
ASTContext &ctx = D->getASTContext();
1051-
return D->getAttrs().getUnavailable(ctx);
1051+
if (auto attr = D->getAttrs().getUnavailable(ctx))
1052+
return attr;
1053+
1054+
// If D is an extension member, check if the extension is unavailable.
1055+
if (auto ext = dyn_cast<ExtensionDecl>(D->getDeclContext()))
1056+
return AvailableAttr::isUnavailable(ext);
1057+
1058+
return nullptr;
10521059
}
10531060

10541061
SpecializeAttr::SpecializeAttr(SourceLoc atLoc, SourceRange range,

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,13 +1503,17 @@ static bool isInsideUnavailableDeclaration(SourceRange ReferenceRange,
15031503
/// Returns true if the reference or any of its parents is an
15041504
/// unconditional unavailable declaration for the same platform.
15051505
static bool isInsideCompatibleUnavailableDeclaration(
1506-
SourceRange ReferenceRange, const DeclContext *ReferenceDC,
1507-
const AvailableAttr *attr) {
1506+
const ValueDecl *referencedD, SourceRange ReferenceRange,
1507+
const DeclContext *ReferenceDC, const AvailableAttr *attr) {
15081508
if (!attr->isUnconditionallyUnavailable()) {
15091509
return false;
15101510
}
1511+
1512+
// Refuse calling unavailable functions from unavailable code,
1513+
// but allow the use of types.
15111514
PlatformKind platform = attr->Platform;
1512-
if (platform == PlatformKind::none) {
1515+
if (platform == PlatformKind::none &&
1516+
!isa<TypeDecl>(referencedD)) {
15131517
return false;
15141518
}
15151519

@@ -2129,7 +2133,7 @@ bool swift::diagnoseExplicitUnavailability(
21292133
// unavailability is OK -- the eventual caller can't call the
21302134
// enclosing code in the same situations it wouldn't be able to
21312135
// call this code.
2132-
if (isInsideCompatibleUnavailableDeclaration(R, DC, Attr)) {
2136+
if (isInsideCompatibleUnavailableDeclaration(D, R, DC, Attr)) {
21332137
return false;
21342138
}
21352139

test/attr/attr_availability.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,3 +1069,16 @@ func rdar46348825_deprecated() {}
10691069
@available(swift, obsoleted: 4.0, obsoleted: 4.0)
10701070
// expected-warning@-1 {{'obsoleted' argument has already been specified}}
10711071
func rdar46348825_obsoleted() {}
1072+
1073+
// Referencing unavailable types in signatures of unavailable functions should be accepted
1074+
@available(*, unavailable)
1075+
protocol UnavailableProto {
1076+
}
1077+
1078+
@available(*, unavailable)
1079+
func unavailableFunc(_ arg: UnavailableProto) -> UnavailableProto {}
1080+
1081+
@available(*, unavailable)
1082+
struct S {
1083+
var a: UnavailableProto
1084+
}

test/attr/attr_availability_osx.swift

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,60 @@ func testAccessors() {
141141
t.unavailableSetter = .init() // expected-error {{setter for 'unavailableSetter' is unavailable in macOS: bad setter}}
142142
t.unavailableSetter.mutate() // expected-error {{setter for 'unavailableSetter' is unavailable in macOS: bad setter}}
143143
}
144+
145+
// Check available on extensions
146+
147+
@available(macOS, unavailable)
148+
extension TestStruct {
149+
func unavailInExtension() {} // expected-note 2 {{'unavailInExtension()' has been explicitly marked unavailable here}}
150+
}
151+
152+
@available(macOS, obsoleted: 10.0)
153+
extension TestStruct {
154+
func obsoletedInExtension() {} // expected-note 2 {{'obsoletedInExtension()' was obsoleted in macOS 10.0}}
155+
}
156+
157+
@available(macOS, deprecated: 10.0)
158+
extension TestStruct {
159+
func deprecatedInExtension() {}
160+
}
161+
162+
@available(swift, introduced: 50.0)
163+
extension TestStruct {
164+
func introducedInExtensionSwift() {} // expected-note 2 {{'introducedInExtensionSwift()' was introduced in Swift 50.0}}
165+
}
166+
167+
@available(macOS, introduced: 10.50)
168+
extension TestStruct {
169+
func introducedInExtensionMacOS() {}
170+
}
171+
172+
TestStruct().unavailInExtension() // expected-error {{'unavailInExtension()' is unavailable in macOS}}
173+
TestStruct().obsoletedInExtension() // expected-error {{'obsoletedInExtension()' is unavailable}}
174+
TestStruct().deprecatedInExtension() // expected-warning {{'deprecatedInExtension()' was deprecated in macOS 10.0}}
175+
TestStruct().introducedInExtensionSwift() // expected-error {{'introducedInExtensionSwift()' is unavailable}}
176+
TestStruct().introducedInExtensionMacOS() // expected-error {{'introducedInExtensionMacOS()' is only available in macOS 10.50 or newer}}
177+
// expected-note@-1{{add 'if #available' version check}}
178+
179+
extension TestStruct {
180+
func availableFunc() {
181+
unavailInExtension() // expected-error {{'unavailInExtension()' is unavailable in macOS}}
182+
obsoletedInExtension() // expected-error {{'obsoletedInExtension()' is unavailable}}
183+
deprecatedInExtension() // expected-warning {{'deprecatedInExtension()' was deprecated in macOS 10.0}}
184+
introducedInExtensionSwift() // expected-error {{'introducedInExtensionSwift()' is unavailable}}
185+
}
186+
}
187+
188+
extension TestStruct { // expected-note{{add @available attribute to enclosing extension}}
189+
func availableFuncMacOS() { // expected-note{{add @available attribute to enclosing instance method}}
190+
introducedInExtensionMacOS() // expected-error {{'introducedInExtensionMacOS()' is only available in macOS 10.50 or newer}}
191+
// expected-note@-1{{add 'if #available' version check}}
192+
}
193+
}
194+
195+
@available(macOS, introduced: 10.50)
196+
extension TestStruct {
197+
func futureFuncMacOS() {
198+
introducedInExtensionMacOS()
199+
}
200+
}

test/attr/attr_availability_swift.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@ extension TestStruct {
2929
func doTheThing() {} // expected-note {{'doTheThing()' was introduced in Swift 400}}
3030
}
3131

32-
@available(swift 400) // FIXME: This has no effect and should be complained about.
32+
@available(swift 400)
3333
extension TestStruct {
34-
func doAnotherThing() {}
34+
func doAnotherThing() {} // expected-note {{'doAnotherThing()' was introduced in Swift 400}}
3535
}
3636

3737
@available(macOS 10.11, *)
3838
func testMemberAvailability() {
3939
TestStruct().doTheThing() // expected-error {{'doTheThing()' is unavailable}}
40-
TestStruct().doAnotherThing() // okay (for now)
40+
TestStruct().doAnotherThing() // expected-error {{'doAnotherThing()' is unavailable}}
4141
}
4242

4343
@available(swift 400) // FIXME: This has no effect and should be complained about.

0 commit comments

Comments
 (0)