Skip to content

Commit

Permalink
[Sema] Consider unavailable functions as being unreachable
Browse files Browse the repository at this point in the history
This has the effect of rejecting unavailable overrides to available
methods in a similar way as overrides that are less available than the
introduction are rejected.
  • Loading branch information
xymus committed Oct 9, 2020
1 parent 53e04cb commit 2f182c2
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 12 deletions.
16 changes: 13 additions & 3 deletions lib/AST/Availability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,13 @@ static bool isBetterThan(const AvailableAttr *newAttr,
return true;

// If they belong to the same platform, the one that introduces later wins.
if (prevAttr->Platform == newAttr->Platform)
if (prevAttr->Platform == newAttr->Platform) {
if (newAttr->isUnconditionallyUnavailable())
return true;
if (prevAttr->isUnconditionallyUnavailable())
return false;
return prevAttr->Introduced.getValue() < newAttr->Introduced.getValue();
}

// If the new attribute's platform inherits from the old one, it wins.
return inheritsAvailabilityFromPlatform(newAttr->Platform,
Expand All @@ -158,10 +163,12 @@ AvailabilityInference::annotatedAvailableRange(const Decl *D, ASTContext &Ctx) {

for (auto Attr : D->getAttrs()) {
auto *AvailAttr = dyn_cast<AvailableAttr>(Attr);
if (AvailAttr == nullptr || !AvailAttr->Introduced.hasValue() ||
if (AvailAttr == nullptr ||
!AvailAttr->isActivePlatform(Ctx) ||
AvailAttr->isLanguageVersionSpecific() ||
AvailAttr->isPackageDescriptionVersionSpecific()) {
AvailAttr->isPackageDescriptionVersionSpecific() ||
(!AvailAttr->Introduced.hasValue() &&
!AvailAttr->isUnconditionallyUnavailable())) {
continue;
}

Expand All @@ -172,6 +179,9 @@ AvailabilityInference::annotatedAvailableRange(const Decl *D, ASTContext &Ctx) {
if (!bestAvailAttr)
return None;

if (bestAvailAttr->isUnconditionallyUnavailable())
return AvailabilityContext(VersionRange::empty());

return AvailabilityContext{
VersionRange::allGTE(bestAvailAttr->Introduced.getValue())};
}
Expand Down
5 changes: 1 addition & 4 deletions test/SILGen/vtables.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ class C : B {
// CHECK: #A.bar: {{.*}} : @$s7vtables1CC3bar{{[_0-9a-zA-Z]*}}F
// CHECK: #A.bas: {{.*}} : @$s7vtables1AC3bas{{[_0-9a-zA-Z]*}}F
// CHECK: #A.qux: {{.*}} : @$s7vtables1CC3qux{{[_0-9a-zA-Z]*}}F
// CHECK: #A.flux: {{.*}} : @$s7vtables1BC4flux{{[_0-9a-zA-Z]*}}F
// CHECK: #B.init!allocator: {{.*}} : @$s7vtables1CC{{[_0-9a-zA-Z]*}}fC
// CHECK: #B.zim: {{.*}} : @$s7vtables1BC3zim{{[_0-9a-zA-Z]*}}F
// CHECK: #B.zang: {{.*}} : @$s7vtables1CC4zang{{[_0-9a-zA-Z]*}}F
Expand All @@ -35,7 +34,7 @@ class A {
func bar() {}
func bas() {}
func qux() {}
func flux() {}
@available(*, unavailable) func flux() {}
}

// CHECK: sil_vtable A {
Expand All @@ -54,7 +53,6 @@ class B : A {
// bar inherited from A
// bas inherited from A
override func qux() {}
@available(*, unavailable) override func flux() {}

func zim() {}
func zang() {}
Expand All @@ -65,7 +63,6 @@ class B : A {
// CHECK: #A.bar: {{.*}} : @$s7vtables1AC3bar{{[_0-9a-zA-Z]*}}F
// CHECK: #A.bas: {{.*}} : @$s7vtables1AC3bas{{[_0-9a-zA-Z]*}}F
// CHECK: #A.qux: {{.*}} : @$s7vtables1BC3qux{{[_0-9a-zA-Z]*}}F
// CHECK: #A.flux: {{.*}} : @$s7vtables1BC4flux{{[_0-9a-zA-Z]*}}F
// CHECK: #B.init!allocator: {{.*}} : @$s7vtables1BC{{[_0-9a-zA-Z]*}}fC
// CHECK: #B.zim: {{.*}} : @$s7vtables1BC3zim{{[_0-9a-zA-Z]*}}F
// CHECK: #B.zang: {{.*}} : @$s7vtables1BC4zang{{[_0-9a-zA-Z]*}}F
Expand Down
5 changes: 5 additions & 0 deletions test/Sema/availability_refinement_contexts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,11 @@ func functionWithWhile() {
public func olderFunction() {
}

// CHECK-NEXT: {{^}} (decl versions=empty explicit=empty decl=unavailableFunction()
@available(macOS, unavailable)
public func unavailableFunction() {
}

// CHECK-NEXT: {{^}} (decl versions=[10.10,+Inf) explicit=[10.10,+Inf) decl=inlinableFunction()
// CHECK-NEXT: {{^}} (condition_following_availability versions=[10.55,+Inf) explicit=[10.55,+Inf)
// CHECK-NEXT: {{^}} (if_then versions=[10.55,+Inf) explicit=[10.55,+Inf)
Expand Down
33 changes: 29 additions & 4 deletions test/Sema/availability_versions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -788,21 +788,21 @@ class UnavailableClassExtendingUnavailableClass : ClassAvailableOn10_51 {
// Method availability is contravariant

class SuperWithAlwaysAvailableMembers {
func shouldAlwaysBeAvailableMethod() { // expected-note {{overridden declaration is here}}
func shouldAlwaysBeAvailableMethod() { // expected-note 2 {{overridden declaration is here}}
}

var shouldAlwaysBeAvailableProperty: Int { // expected-note {{overridden declaration is here}}
var shouldAlwaysBeAvailableProperty: Int { // expected-note 2 {{overridden declaration is here}}
get { return 9 }
set(newVal) {}
}

var setterShouldAlwaysBeAvailableProperty: Int {
get { return 9 }
set(newVal) {} // expected-note {{overridden declaration is here}}
set(newVal) {} // expected-note 2 {{overridden declaration is here}}
}

var getterShouldAlwaysBeAvailableProperty: Int {
get { return 9 } // expected-note {{overridden declaration is here}}
get { return 9 } // expected-note 2 {{overridden declaration is here}}
set(newVal) {}
}
}
Expand Down Expand Up @@ -832,6 +832,31 @@ class SubWithLimitedMemberAvailability : SuperWithAlwaysAvailableMembers {
}
}

class SubWithUnavailableMembers : SuperWithAlwaysAvailableMembers {
@available(OSX, unavailable)
override func shouldAlwaysBeAvailableMethod() { // expected-error {{overriding 'shouldAlwaysBeAvailableMethod' must be as available as declaration it overrides}}
}

@available(OSX, unavailable)
override var shouldAlwaysBeAvailableProperty: Int { // expected-error {{overriding 'shouldAlwaysBeAvailableProperty' must be as available as declaration it overrides}}
get { return 10 }
set(newVal) {}
}

override var setterShouldAlwaysBeAvailableProperty: Int {
get { return 9 }
@available(OSX, unavailable)
set(newVal) {} // expected-error {{overriding setter for 'setterShouldAlwaysBeAvailableProperty' must be as available as declaration it overrides}}
// This is a terrible diagnostic. rdar://problem/20427938
}

override var getterShouldAlwaysBeAvailableProperty: Int {
@available(OSX, unavailable)
get { return 9 } // expected-error {{overriding getter for 'getterShouldAlwaysBeAvailableProperty' must be as available as declaration it overrides}}
set(newVal) {}
}
}

class SuperWithLimitedMemberAvailability {
@available(OSX, introduced: 10.51)
func someMethod() {
Expand Down
21 changes: 20 additions & 1 deletion test/attr/attr_availability_maccatalyst.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: %swift -typecheck -verify -parse-stdlib -target x86_64-apple-ios51.0-macabi %s

// REQUIRES: OS=maccatalyst
// REQUIRES: VENDOR=apple

@available(macCatalyst, introduced: 1.0, deprecated: 2.0, obsoleted: 9.0,
message: "you don't want to do that anyway")
Expand Down Expand Up @@ -52,6 +52,16 @@ func introducedLaterOnMacCatalyst() {
func introducedLaterOnIOS() {
}

@available(iOS, introduced: 1.0)
@available(macCatalyst, unavailable)
func unavailableOnMacCatalyst() { // expected-note 3 {{'unavailableOnMacCatalyst()' has been explicitly marked unavailable here}}
}

@available(iOS, unavailable)
@available(macCatalyst, introduced: 1.0)
func unavailableOnIOS() {
}

// expected-note@+1 *{{add @available attribute to enclosing global function}}
func testPoundAvailable() {

Expand All @@ -60,6 +70,9 @@ func testPoundAvailable() {
// expected-note@-1 {{add 'if #available' version check}}
introducedLaterOnIOS() // expected-error {{'introducedLaterOnIOS()' is only available in Mac Catalyst 56.0 or newer}}
// expected-note@-1 {{add 'if #available' version check}}

unavailableOnMacCatalyst() // expected-error {{'unavailableOnMacCatalyst()' is unavailable in Mac Catalyst}}
unavailableOnIOS()
}

// macCatalyst should win over iOS when present
Expand All @@ -69,6 +82,9 @@ func testPoundAvailable() {
// expected-note@-1 {{add 'if #available' version check}}
introducedLaterOnIOS() // expected-error {{'introducedLaterOnIOS()' is only available in Mac Catalyst 56.0 or newer}}
// expected-note@-1 {{add 'if #available' version check}}

unavailableOnMacCatalyst() // expected-error {{'unavailableOnMacCatalyst()' is unavailable in Mac Catalyst}}
unavailableOnIOS()
}

if #available(iOS 55.0, macCatalyst 56.0, *) {
Expand All @@ -88,6 +104,9 @@ func testPoundAvailable() {
// expected-note@-1 {{add 'if #available' version check}}
introducedLaterOnIOS() // expected-error {{'introducedLaterOnIOS()' is only available in Mac Catalyst 56.0 or newer}}
// expected-note@-1 {{add 'if #available' version check}}

unavailableOnMacCatalyst() // expected-error {{'unavailableOnMacCatalyst()' is unavailable in Mac Catalyst}}
unavailableOnIOS()
}

if #available(iOS 56.0, *) {
Expand Down

0 comments on commit 2f182c2

Please sign in to comment.