Skip to content

Commit 94a4d84

Browse files
authored
Merge pull request #58680 from tshortli/unavailable-wins
Sema: Members with availability in unavailable containers should be unavailable
2 parents c1554f6 + c78090b commit 94a4d84

File tree

3 files changed

+90
-31
lines changed

3 files changed

+90
-31
lines changed

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,30 @@ static bool computeContainedByDeploymentTarget(TypeRefinementContext *TRC,
334334
.isContainedIn(AvailabilityContext::forDeploymentTarget(ctx));
335335
}
336336

337+
/// Returns true if the reference or any of its parents is an
338+
/// unconditional unavailable declaration for the same platform.
339+
static bool isInsideCompatibleUnavailableDeclaration(
340+
const Decl *D, const ExportContext &where, const AvailableAttr *attr) {
341+
auto referencedPlatform = where.getUnavailablePlatformKind();
342+
if (!referencedPlatform)
343+
return false;
344+
345+
if (!attr->isUnconditionallyUnavailable()) {
346+
return false;
347+
}
348+
349+
// Refuse calling unavailable functions from unavailable code,
350+
// but allow the use of types.
351+
PlatformKind platform = attr->Platform;
352+
if (platform == PlatformKind::none && !isa<TypeDecl>(D) &&
353+
!isa<ExtensionDecl>(D)) {
354+
return false;
355+
}
356+
357+
return (*referencedPlatform == platform ||
358+
inheritsAvailabilityFromPlatform(platform, *referencedPlatform));
359+
}
360+
337361
namespace {
338362

339363
/// A class to walk the AST to build the type refinement context hierarchy.
@@ -1192,6 +1216,12 @@ bool TypeChecker::isDeclarationUnavailable(
11921216
Optional<UnavailabilityReason>
11931217
TypeChecker::checkDeclarationAvailability(const Decl *D,
11941218
const ExportContext &Where) {
1219+
// Skip computing potential unavailability if the declaration is explicitly
1220+
// unavailable and the context is also unavailable.
1221+
if (const AvailableAttr *Attr = AvailableAttr::isUnavailable(D))
1222+
if (isInsideCompatibleUnavailableDeclaration(D, Where, Attr))
1223+
return None;
1224+
11951225
if (isDeclarationUnavailable(D, Where.getDeclContext(), [&Where] {
11961226
return Where.getAvailabilityContext();
11971227
})) {
@@ -2014,33 +2044,6 @@ const AvailableAttr *TypeChecker::getDeprecated(const Decl *D) {
20142044
return nullptr;
20152045
}
20162046

2017-
/// Returns true if the reference or any of its parents is an
2018-
/// unconditional unavailable declaration for the same platform.
2019-
static bool isInsideCompatibleUnavailableDeclaration(
2020-
const Decl *D, const ExportContext &where,
2021-
const AvailableAttr *attr) {
2022-
auto referencedPlatform = where.getUnavailablePlatformKind();
2023-
if (!referencedPlatform)
2024-
return false;
2025-
2026-
if (!attr->isUnconditionallyUnavailable()) {
2027-
return false;
2028-
}
2029-
2030-
// Refuse calling unavailable functions from unavailable code,
2031-
// but allow the use of types.
2032-
PlatformKind platform = attr->Platform;
2033-
if (platform == PlatformKind::none &&
2034-
!isa<TypeDecl>(D) &&
2035-
!isa<ExtensionDecl>(D)) {
2036-
return false;
2037-
}
2038-
2039-
return (*referencedPlatform == platform ||
2040-
inheritsAvailabilityFromPlatform(platform,
2041-
*referencedPlatform));
2042-
}
2043-
20442047
static void fixItAvailableAttrRename(InFlightDiagnostic &diag,
20452048
SourceRange referenceRange,
20462049
const ValueDecl *renamedDecl,

test/Sema/availability_versions.swift

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,10 +1632,6 @@ func funcWithMultipleShortFormAnnotationsForTheSamePlatform() {
16321632
// expected-note@-1 {{add 'if #available' version check}}
16331633
}
16341634

1635-
@available(OSX 10.9, *)
1636-
@available(OSX, unavailable)
1637-
func unavailableWins() { } // expected-note {{'unavailableWins()' has been explicitly marked unavailable here}}
1638-
16391635
func useShortFormAvailable() {
16401636
// expected-note@-1 4{{add @available attribute to enclosing global function}}
16411637

@@ -1654,6 +1650,34 @@ func useShortFormAvailable() {
16541650

16551651
funcWithMultipleShortFormAnnotationsForTheSamePlatform() // expected-error {{'funcWithMultipleShortFormAnnotationsForTheSamePlatform()' is only available in macOS 10.53 or newer}}
16561652
// expected-note@-1 {{add 'if #available' version check}}
1653+
}
1654+
1655+
// Unavailability takes precedence over availability and is inherited
1656+
1657+
@available(OSX 10.9, *)
1658+
@available(OSX, unavailable)
1659+
func unavailableWins() { }
1660+
// expected-note@-1 {{'unavailableWins()' has been explicitly marked unavailable here}}
1661+
1662+
struct HasUnavailableExtension {
1663+
@available(OSX, unavailable)
1664+
public func directlyUnavailable() { }
1665+
// expected-note@-1 {{'directlyUnavailable()' has been explicitly marked unavailable here}}
1666+
}
1667+
1668+
@available(OSX, unavailable)
1669+
extension HasUnavailableExtension {
1670+
public func inheritsUnavailable() { }
1671+
// expected-note@-1 {{'inheritsUnavailable()' has been explicitly marked unavailable here}}
1672+
1673+
@available(OSX 10.9, *)
1674+
public func moreAvailableButStillUnavailable() { }
1675+
// expected-note@-1 {{'moreAvailableButStillUnavailable()' has been explicitly marked unavailable here}}
1676+
}
16571677

1678+
func useHasUnavailableExtension(_ s: HasUnavailableExtension) {
16581679
unavailableWins() // expected-error {{'unavailableWins()' is unavailable}}
1680+
s.directlyUnavailable() // expected-error {{'directlyUnavailable()' is unavailable}}
1681+
s.inheritsUnavailable() // expected-error {{'inheritsUnavailable()' is unavailable in macOS}}
1682+
s.moreAvailableButStillUnavailable() // expected-error {{'moreAvailableButStillUnavailable()' is unavailable in macOS}}
16591683
}

test/attr/attr_availability_transitive_osx.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,39 @@ extension Outer {
106106

107107
@available(OSX, unavailable)
108108
extension Outer {
109+
// expected-note@+1 {{'outer_osx_init_osx' has been explicitly marked unavailable here}}
109110
static var outer_osx_init_osx = osx() // OK
111+
112+
// expected-note@+1 {{'osx_call_osx()' has been explicitly marked unavailable here}}
113+
func osx_call_osx() {
114+
osx() // OK
115+
}
116+
117+
func osx_call_osx_extension() {
118+
osx_extension() // OK; osx_extension is only unavailable if -application-extension is passed.
119+
}
120+
121+
func takes_and_returns_osx(_ x: NotOnOSX) -> NotOnOSX {
122+
return x // OK
123+
}
124+
125+
// This @available should be ignored; inherited unavailability takes precedence
126+
@available(OSX 999, *)
127+
// expected-note@+1 {{'osx_more_available_but_still_unavailable_call_osx()' has been explicitly marked unavailable here}}
128+
func osx_more_available_but_still_unavailable_call_osx() {
129+
osx() // OK
130+
}
131+
132+
// rdar://92551870
133+
func osx_call_osx_more_available_but_still_unavailable() {
134+
osx_more_available_but_still_unavailable_call_osx() // OK
135+
}
136+
}
137+
138+
func takesOuter(_ o: Outer) {
139+
_ = Outer.outer_osx_init_osx // expected-error {{'outer_osx_init_osx' is unavailable in macOS}}
140+
o.osx_call_osx() // expected-error {{'osx_call_osx()' is unavailable in macOS}}
141+
o.osx_more_available_but_still_unavailable_call_osx() // expected-error {{'osx_more_available_but_still_unavailable_call_osx()' is unavailable in macOS}}
110142
}
111143

112144
@available(OSX, unavailable)

0 commit comments

Comments
 (0)