Skip to content

Commit f21d9f3

Browse files
committed
Allow @available(swift, ...) nested within @available(macOS, ...)
Previously, we treated this as an attempt to widen the availability of a member beyond its context, but it's really a different axis of availability. Also, warn about using @available on extensions without an OS, which we just completely ignore right now. rdar://problem/32632327
1 parent 7a6c880 commit f21d9f3

File tree

5 files changed

+81
-2
lines changed

5 files changed

+81
-2
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3647,6 +3647,10 @@ WARNING(availability_query_useless_enclosing_scope, none,
36473647
NOTE(availability_query_useless_enclosing_scope_here, none,
36483648
"enclosing scope here", ())
36493649

3650+
WARNING(availability_extension_platform_agnostic, none,
3651+
"'@available' without an OS is ignored on extensions; "
3652+
"apply the attribute to each member instead", ())
3653+
36503654
ERROR(availability_global_script_no_potential,
36513655
none, "global variable cannot be marked potentially "
36523656
"unavailable with '@available' in script mode", ())

lib/Sema/TypeCheckAttr.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ class AttributeEarlyChecker : public AttributeVisitor<AttributeEarlyChecker> {
7070
bool visitDeclAttribute(DeclAttribute *A) = delete;
7171

7272
#define IGNORED_ATTR(X) void visit##X##Attr(X##Attr *) {}
73-
IGNORED_ATTR(Available)
7473
IGNORED_ATTR(CDecl)
7574
IGNORED_ATTR(ClangImporterSynthesizedType)
7675
IGNORED_ATTR(Convenience)
@@ -115,6 +114,14 @@ class AttributeEarlyChecker : public AttributeVisitor<AttributeEarlyChecker> {
115114
IGNORED_ATTR(WeakLinked)
116115
#undef IGNORED_ATTR
117116

117+
void visitAvailableAttr(AvailableAttr *attr) {
118+
if (!isa<ExtensionDecl>(D))
119+
return;
120+
if (attr->hasPlatform())
121+
return;
122+
diagnoseAndRemoveAttr(attr, diag::availability_extension_platform_agnostic);
123+
}
124+
118125
// @noreturn has been replaced with a 'Never' return type.
119126
void visitNoReturnAttr(NoReturnAttr *attr) {
120127
if (auto FD = dyn_cast<FuncDecl>(D)) {
@@ -1073,8 +1080,10 @@ void AttributeChecker::visitAvailableAttr(AvailableAttr *attr) {
10731080
if (TC.getLangOpts().DisableAvailabilityChecking)
10741081
return;
10751082

1076-
if (!attr->isActivePlatform(TC.Context) || !attr->Introduced.hasValue())
1083+
if (!attr->hasPlatform() || !attr->isActivePlatform(TC.Context) ||
1084+
!attr->Introduced.hasValue()) {
10771085
return;
1086+
}
10781087

10791088
SourceLoc attrLoc = attr->getLocation();
10801089

test/attr/attr_availability.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,3 +807,9 @@ rdar32526620_2(a: 42, b: .bar)
807807
func rdar32526620_3(a: Int, b: E_32526620, c: String) {} // expected-note {{here}}
808808
rdar32526620_3(a: 42, b: .bar, c: "question")
809809
// expected-error@-1 {{'rdar32526620_3(a:b:c:)' has been replaced by instance method 'E_32526620.set(a:c:)'}} {{1-15=E_32526620.bar.set}} {{23-32=}}
810+
811+
@available(*, unavailable) // expected-warning {{'@available' without an OS is ignored on extensions; apply the attribute to each member instead}} {{1-28=}}
812+
extension DummyType {}
813+
814+
@available(*, deprecated) // expected-warning {{'@available' without an OS is ignored on extensions; apply the attribute to each member instead}} {{1-27=}}
815+
extension DummyType {}

test/attr/attr_availability_osx.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,36 @@ doSomethingDeprecatedOnOSX() // expected-warning{{'doSomethingDeprecatedOnOSX()'
7171
func doSomethingDeprecatedOniOS() { }
7272

7373
doSomethingDeprecatedOniOS() // okay
74+
75+
76+
struct TestStruct {}
77+
78+
@available(macOS 10.10, *)
79+
extension TestStruct { // expected-note {{enclosing scope here}}
80+
@available(swift 400)
81+
func doTheThing() {} // expected-note {{'doTheThing()' was introduced in Swift 400}}
82+
83+
@available(macOS 10.9, *) // expected-error {{declaration cannot be more available than enclosing scope}}
84+
@available(swift 400)
85+
func doAnotherThing() {} // expected-note {{'doAnotherThing()' was introduced in Swift 400}}
86+
87+
@available(macOS 10.12, *)
88+
@available(swift 400)
89+
func doThirdThing() {} // expected-note {{'doThirdThing()' was introduced in Swift 400}}
90+
91+
@available(macOS 10.12, *)
92+
@available(swift 1)
93+
func doFourthThing() {}
94+
95+
@available(*, deprecated)
96+
func doDeprecatedThing() {}
97+
}
98+
99+
@available(macOS 10.11, *)
100+
func testMemberAvailability() {
101+
TestStruct().doTheThing() // expected-error {{'doTheThing()' is unavailable}}
102+
TestStruct().doAnotherThing() // expected-error {{'doAnotherThing()' is unavailable}}
103+
TestStruct().doThirdThing() // expected-error {{'doThirdThing()' is unavailable}}
104+
TestStruct().doFourthThing() // expected-error {{'doFourthThing()' is only available on OS X 10.12 or newer}} expected-note {{'if #available'}}
105+
TestStruct().doDeprecatedThing() // expected-warning {{'doDeprecatedThing()' is deprecated}}
106+
}

test/attr/attr_availability_swift.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,30 @@ func baz() {
2020
@available(swift, introduced: 3.0.1, obsoleted: 3.0.2, message: "tiny bug")
2121
func bug() {
2222
}
23+
24+
struct TestStruct {}
25+
26+
@available(macOS 10.11, *)
27+
extension TestStruct {
28+
@available(swift 400)
29+
func doTheThing() {} // expected-note {{'doTheThing()' was introduced in Swift 400}}
30+
}
31+
32+
@available(swift 400) // expected-warning {{'@available' without an OS is ignored on extensions; apply the attribute to each member instead}} {{1-23=}}
33+
extension TestStruct {
34+
func doAnotherThing() {}
35+
}
36+
37+
@available(macOS 10.11, *)
38+
func testMemberAvailability() {
39+
TestStruct().doTheThing() // expected-error {{'doTheThing()' is unavailable}}
40+
TestStruct().doAnotherThing() // okay (for now)
41+
}
42+
43+
@available(swift 400) // expected-warning {{'@available' without an OS is ignored on extensions; apply the attribute to each member instead}} {{1-23=}}
44+
@available(macOS 10.11, *)
45+
extension TestStruct {}
46+
47+
@available(macOS 10.11, *)
48+
@available(swift 400) // expected-warning {{'@available' without an OS is ignored on extensions; apply the attribute to each member instead}} {{1-23=}}
49+
extension TestStruct {}

0 commit comments

Comments
 (0)