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
This commit is contained in:
Jordan Rose
2018-03-14 16:37:36 -07:00
parent 7a6c88020f
commit f21d9f332d
5 changed files with 81 additions and 2 deletions

View File

@@ -3647,6 +3647,10 @@ WARNING(availability_query_useless_enclosing_scope, none,
NOTE(availability_query_useless_enclosing_scope_here, none,
"enclosing scope here", ())
WARNING(availability_extension_platform_agnostic, none,
"'@available' without an OS is ignored on extensions; "
"apply the attribute to each member instead", ())
ERROR(availability_global_script_no_potential,
none, "global variable cannot be marked potentially "
"unavailable with '@available' in script mode", ())

View File

@@ -70,7 +70,6 @@ public:
bool visitDeclAttribute(DeclAttribute *A) = delete;
#define IGNORED_ATTR(X) void visit##X##Attr(X##Attr *) {}
IGNORED_ATTR(Available)
IGNORED_ATTR(CDecl)
IGNORED_ATTR(ClangImporterSynthesizedType)
IGNORED_ATTR(Convenience)
@@ -115,6 +114,14 @@ public:
IGNORED_ATTR(WeakLinked)
#undef IGNORED_ATTR
void visitAvailableAttr(AvailableAttr *attr) {
if (!isa<ExtensionDecl>(D))
return;
if (attr->hasPlatform())
return;
diagnoseAndRemoveAttr(attr, diag::availability_extension_platform_agnostic);
}
// @noreturn has been replaced with a 'Never' return type.
void visitNoReturnAttr(NoReturnAttr *attr) {
if (auto FD = dyn_cast<FuncDecl>(D)) {
@@ -1073,8 +1080,10 @@ void AttributeChecker::visitAvailableAttr(AvailableAttr *attr) {
if (TC.getLangOpts().DisableAvailabilityChecking)
return;
if (!attr->isActivePlatform(TC.Context) || !attr->Introduced.hasValue())
if (!attr->hasPlatform() || !attr->isActivePlatform(TC.Context) ||
!attr->Introduced.hasValue()) {
return;
}
SourceLoc attrLoc = attr->getLocation();

View File

@@ -807,3 +807,9 @@ rdar32526620_2(a: 42, b: .bar)
func rdar32526620_3(a: Int, b: E_32526620, c: String) {} // expected-note {{here}}
rdar32526620_3(a: 42, b: .bar, c: "question")
// 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=}}
@available(*, unavailable) // expected-warning {{'@available' without an OS is ignored on extensions; apply the attribute to each member instead}} {{1-28=}}
extension DummyType {}
@available(*, deprecated) // expected-warning {{'@available' without an OS is ignored on extensions; apply the attribute to each member instead}} {{1-27=}}
extension DummyType {}

View File

@@ -71,3 +71,36 @@ doSomethingDeprecatedOnOSX() // expected-warning{{'doSomethingDeprecatedOnOSX()'
func doSomethingDeprecatedOniOS() { }
doSomethingDeprecatedOniOS() // okay
struct TestStruct {}
@available(macOS 10.10, *)
extension TestStruct { // expected-note {{enclosing scope here}}
@available(swift 400)
func doTheThing() {} // expected-note {{'doTheThing()' was introduced in Swift 400}}
@available(macOS 10.9, *) // expected-error {{declaration cannot be more available than enclosing scope}}
@available(swift 400)
func doAnotherThing() {} // expected-note {{'doAnotherThing()' was introduced in Swift 400}}
@available(macOS 10.12, *)
@available(swift 400)
func doThirdThing() {} // expected-note {{'doThirdThing()' was introduced in Swift 400}}
@available(macOS 10.12, *)
@available(swift 1)
func doFourthThing() {}
@available(*, deprecated)
func doDeprecatedThing() {}
}
@available(macOS 10.11, *)
func testMemberAvailability() {
TestStruct().doTheThing() // expected-error {{'doTheThing()' is unavailable}}
TestStruct().doAnotherThing() // expected-error {{'doAnotherThing()' is unavailable}}
TestStruct().doThirdThing() // expected-error {{'doThirdThing()' is unavailable}}
TestStruct().doFourthThing() // expected-error {{'doFourthThing()' is only available on OS X 10.12 or newer}} expected-note {{'if #available'}}
TestStruct().doDeprecatedThing() // expected-warning {{'doDeprecatedThing()' is deprecated}}
}

View File

@@ -20,3 +20,30 @@ func baz() {
@available(swift, introduced: 3.0.1, obsoleted: 3.0.2, message: "tiny bug")
func bug() {
}
struct TestStruct {}
@available(macOS 10.11, *)
extension TestStruct {
@available(swift 400)
func doTheThing() {} // expected-note {{'doTheThing()' was introduced in Swift 400}}
}
@available(swift 400) // expected-warning {{'@available' without an OS is ignored on extensions; apply the attribute to each member instead}} {{1-23=}}
extension TestStruct {
func doAnotherThing() {}
}
@available(macOS 10.11, *)
func testMemberAvailability() {
TestStruct().doTheThing() // expected-error {{'doTheThing()' is unavailable}}
TestStruct().doAnotherThing() // okay (for now)
}
@available(swift 400) // expected-warning {{'@available' without an OS is ignored on extensions; apply the attribute to each member instead}} {{1-23=}}
@available(macOS 10.11, *)
extension TestStruct {}
@available(macOS 10.11, *)
@available(swift 400) // expected-warning {{'@available' without an OS is ignored on extensions; apply the attribute to each member instead}} {{1-23=}}
extension TestStruct {}