Skip to content

Commit 2f182c2

Browse files
committed
[Sema] Consider unavailable functions as being unreachable
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.
1 parent 53e04cb commit 2f182c2

File tree

5 files changed

+68
-12
lines changed

5 files changed

+68
-12
lines changed

lib/AST/Availability.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,13 @@ static bool isBetterThan(const AvailableAttr *newAttr,
144144
return true;
145145

146146
// If they belong to the same platform, the one that introduces later wins.
147-
if (prevAttr->Platform == newAttr->Platform)
147+
if (prevAttr->Platform == newAttr->Platform) {
148+
if (newAttr->isUnconditionallyUnavailable())
149+
return true;
150+
if (prevAttr->isUnconditionallyUnavailable())
151+
return false;
148152
return prevAttr->Introduced.getValue() < newAttr->Introduced.getValue();
153+
}
149154

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

159164
for (auto Attr : D->getAttrs()) {
160165
auto *AvailAttr = dyn_cast<AvailableAttr>(Attr);
161-
if (AvailAttr == nullptr || !AvailAttr->Introduced.hasValue() ||
166+
if (AvailAttr == nullptr ||
162167
!AvailAttr->isActivePlatform(Ctx) ||
163168
AvailAttr->isLanguageVersionSpecific() ||
164-
AvailAttr->isPackageDescriptionVersionSpecific()) {
169+
AvailAttr->isPackageDescriptionVersionSpecific() ||
170+
(!AvailAttr->Introduced.hasValue() &&
171+
!AvailAttr->isUnconditionallyUnavailable())) {
165172
continue;
166173
}
167174

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

182+
if (bestAvailAttr->isUnconditionallyUnavailable())
183+
return AvailabilityContext(VersionRange::empty());
184+
175185
return AvailabilityContext{
176186
VersionRange::allGTE(bestAvailAttr->Introduced.getValue())};
177187
}

test/SILGen/vtables.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ class C : B {
2121
// CHECK: #A.bar: {{.*}} : @$s7vtables1CC3bar{{[_0-9a-zA-Z]*}}F
2222
// CHECK: #A.bas: {{.*}} : @$s7vtables1AC3bas{{[_0-9a-zA-Z]*}}F
2323
// CHECK: #A.qux: {{.*}} : @$s7vtables1CC3qux{{[_0-9a-zA-Z]*}}F
24-
// CHECK: #A.flux: {{.*}} : @$s7vtables1BC4flux{{[_0-9a-zA-Z]*}}F
2524
// CHECK: #B.init!allocator: {{.*}} : @$s7vtables1CC{{[_0-9a-zA-Z]*}}fC
2625
// CHECK: #B.zim: {{.*}} : @$s7vtables1BC3zim{{[_0-9a-zA-Z]*}}F
2726
// CHECK: #B.zang: {{.*}} : @$s7vtables1CC4zang{{[_0-9a-zA-Z]*}}F
@@ -35,7 +34,7 @@ class A {
3534
func bar() {}
3635
func bas() {}
3736
func qux() {}
38-
func flux() {}
37+
@available(*, unavailable) func flux() {}
3938
}
4039

4140
// CHECK: sil_vtable A {
@@ -54,7 +53,6 @@ class B : A {
5453
// bar inherited from A
5554
// bas inherited from A
5655
override func qux() {}
57-
@available(*, unavailable) override func flux() {}
5856

5957
func zim() {}
6058
func zang() {}
@@ -65,7 +63,6 @@ class B : A {
6563
// CHECK: #A.bar: {{.*}} : @$s7vtables1AC3bar{{[_0-9a-zA-Z]*}}F
6664
// CHECK: #A.bas: {{.*}} : @$s7vtables1AC3bas{{[_0-9a-zA-Z]*}}F
6765
// CHECK: #A.qux: {{.*}} : @$s7vtables1BC3qux{{[_0-9a-zA-Z]*}}F
68-
// CHECK: #A.flux: {{.*}} : @$s7vtables1BC4flux{{[_0-9a-zA-Z]*}}F
6966
// CHECK: #B.init!allocator: {{.*}} : @$s7vtables1BC{{[_0-9a-zA-Z]*}}fC
7067
// CHECK: #B.zim: {{.*}} : @$s7vtables1BC3zim{{[_0-9a-zA-Z]*}}F
7168
// CHECK: #B.zang: {{.*}} : @$s7vtables1BC4zang{{[_0-9a-zA-Z]*}}F

test/Sema/availability_refinement_contexts.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,11 @@ func functionWithWhile() {
198198
public func olderFunction() {
199199
}
200200

201+
// CHECK-NEXT: {{^}} (decl versions=empty explicit=empty decl=unavailableFunction()
202+
@available(macOS, unavailable)
203+
public func unavailableFunction() {
204+
}
205+
201206
// CHECK-NEXT: {{^}} (decl versions=[10.10,+Inf) explicit=[10.10,+Inf) decl=inlinableFunction()
202207
// CHECK-NEXT: {{^}} (condition_following_availability versions=[10.55,+Inf) explicit=[10.55,+Inf)
203208
// CHECK-NEXT: {{^}} (if_then versions=[10.55,+Inf) explicit=[10.55,+Inf)

test/Sema/availability_versions.swift

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -788,21 +788,21 @@ class UnavailableClassExtendingUnavailableClass : ClassAvailableOn10_51 {
788788
// Method availability is contravariant
789789

790790
class SuperWithAlwaysAvailableMembers {
791-
func shouldAlwaysBeAvailableMethod() { // expected-note {{overridden declaration is here}}
791+
func shouldAlwaysBeAvailableMethod() { // expected-note 2 {{overridden declaration is here}}
792792
}
793793

794-
var shouldAlwaysBeAvailableProperty: Int { // expected-note {{overridden declaration is here}}
794+
var shouldAlwaysBeAvailableProperty: Int { // expected-note 2 {{overridden declaration is here}}
795795
get { return 9 }
796796
set(newVal) {}
797797
}
798798

799799
var setterShouldAlwaysBeAvailableProperty: Int {
800800
get { return 9 }
801-
set(newVal) {} // expected-note {{overridden declaration is here}}
801+
set(newVal) {} // expected-note 2 {{overridden declaration is here}}
802802
}
803803

804804
var getterShouldAlwaysBeAvailableProperty: Int {
805-
get { return 9 } // expected-note {{overridden declaration is here}}
805+
get { return 9 } // expected-note 2 {{overridden declaration is here}}
806806
set(newVal) {}
807807
}
808808
}
@@ -832,6 +832,31 @@ class SubWithLimitedMemberAvailability : SuperWithAlwaysAvailableMembers {
832832
}
833833
}
834834

835+
class SubWithUnavailableMembers : SuperWithAlwaysAvailableMembers {
836+
@available(OSX, unavailable)
837+
override func shouldAlwaysBeAvailableMethod() { // expected-error {{overriding 'shouldAlwaysBeAvailableMethod' must be as available as declaration it overrides}}
838+
}
839+
840+
@available(OSX, unavailable)
841+
override var shouldAlwaysBeAvailableProperty: Int { // expected-error {{overriding 'shouldAlwaysBeAvailableProperty' must be as available as declaration it overrides}}
842+
get { return 10 }
843+
set(newVal) {}
844+
}
845+
846+
override var setterShouldAlwaysBeAvailableProperty: Int {
847+
get { return 9 }
848+
@available(OSX, unavailable)
849+
set(newVal) {} // expected-error {{overriding setter for 'setterShouldAlwaysBeAvailableProperty' must be as available as declaration it overrides}}
850+
// This is a terrible diagnostic. rdar://problem/20427938
851+
}
852+
853+
override var getterShouldAlwaysBeAvailableProperty: Int {
854+
@available(OSX, unavailable)
855+
get { return 9 } // expected-error {{overriding getter for 'getterShouldAlwaysBeAvailableProperty' must be as available as declaration it overrides}}
856+
set(newVal) {}
857+
}
858+
}
859+
835860
class SuperWithLimitedMemberAvailability {
836861
@available(OSX, introduced: 10.51)
837862
func someMethod() {

test/attr/attr_availability_maccatalyst.swift

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %swift -typecheck -verify -parse-stdlib -target x86_64-apple-ios51.0-macabi %s
22

3-
// REQUIRES: OS=maccatalyst
3+
// REQUIRES: VENDOR=apple
44

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

55+
@available(iOS, introduced: 1.0)
56+
@available(macCatalyst, unavailable)
57+
func unavailableOnMacCatalyst() { // expected-note 3 {{'unavailableOnMacCatalyst()' has been explicitly marked unavailable here}}
58+
}
59+
60+
@available(iOS, unavailable)
61+
@available(macCatalyst, introduced: 1.0)
62+
func unavailableOnIOS() {
63+
}
64+
5565
// expected-note@+1 *{{add @available attribute to enclosing global function}}
5666
func testPoundAvailable() {
5767

@@ -60,6 +70,9 @@ func testPoundAvailable() {
6070
// expected-note@-1 {{add 'if #available' version check}}
6171
introducedLaterOnIOS() // expected-error {{'introducedLaterOnIOS()' is only available in Mac Catalyst 56.0 or newer}}
6272
// expected-note@-1 {{add 'if #available' version check}}
73+
74+
unavailableOnMacCatalyst() // expected-error {{'unavailableOnMacCatalyst()' is unavailable in Mac Catalyst}}
75+
unavailableOnIOS()
6376
}
6477

6578
// macCatalyst should win over iOS when present
@@ -69,6 +82,9 @@ func testPoundAvailable() {
6982
// expected-note@-1 {{add 'if #available' version check}}
7083
introducedLaterOnIOS() // expected-error {{'introducedLaterOnIOS()' is only available in Mac Catalyst 56.0 or newer}}
7184
// expected-note@-1 {{add 'if #available' version check}}
85+
86+
unavailableOnMacCatalyst() // expected-error {{'unavailableOnMacCatalyst()' is unavailable in Mac Catalyst}}
87+
unavailableOnIOS()
7288
}
7389

7490
if #available(iOS 55.0, macCatalyst 56.0, *) {
@@ -88,6 +104,9 @@ func testPoundAvailable() {
88104
// expected-note@-1 {{add 'if #available' version check}}
89105
introducedLaterOnIOS() // expected-error {{'introducedLaterOnIOS()' is only available in Mac Catalyst 56.0 or newer}}
90106
// expected-note@-1 {{add 'if #available' version check}}
107+
108+
unavailableOnMacCatalyst() // expected-error {{'unavailableOnMacCatalyst()' is unavailable in Mac Catalyst}}
109+
unavailableOnIOS()
91110
}
92111

93112
if #available(iOS 56.0, *) {

0 commit comments

Comments
 (0)