Skip to content

Commit d49c9fa

Browse files
committed
Sema: Improve diagnostics for decls more available than their containers.
Adopt new request-based utilities for looking up the enclosing declaration's availability when type checking an `@available` attribute. This consolidates implementations of the lookup and improves diagnostics by catching more cases where declarations are more available than their containers.
1 parent 6d657c9 commit d49c9fa

File tree

4 files changed

+53
-46
lines changed

4 files changed

+53
-46
lines changed

include/swift/AST/Decl.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,17 +1101,21 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
11011101
/// Retrieve the @available attribute that provides the OS version range that
11021102
/// this declaration is available in.
11031103
///
1104-
/// The attribute may come from another declaration, since availability
1105-
/// could be inherited from a parent declaration.
1104+
/// This attribute may come from an enclosing decl since availability is
1105+
/// inherited. The second member of the returned pair is the decl that owns
1106+
/// the attribute.
11061107
Optional<std::pair<const AvailableAttr *, const Decl *>>
11071108
getSemanticAvailableRangeAttr() const;
11081109

11091110
/// Retrieve the @available attribute that makes this declaration unavailable,
11101111
/// if any.
11111112
///
1112-
/// The attribute may come from another declaration, since unavailability
1113-
/// could be inherited from a parent declaration. This is a broader notion of
1114-
/// unavailability than is checked by \c AvailableAttr::isUnavailable.
1113+
/// This attribute may come from an enclosing decl since availability is
1114+
/// inherited. The second member of the returned pair is the decl that owns
1115+
/// the attribute.
1116+
///
1117+
/// Note that this notion of unavailability is broader than that which is
1118+
/// checked by \c AvailableAttr::isUnavailable.
11151119
Optional<std::pair<const AvailableAttr *, const Decl *>>
11161120
getSemanticUnavailableAttr() const;
11171121

lib/Sema/TypeCheckAttr.cpp

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1877,56 +1877,54 @@ void AttributeChecker::visitAvailableAttr(AvailableAttr *attr) {
18771877

18781878
SourceLoc attrLoc = attr->getLocation();
18791879

1880+
AvailabilityContext AttrRange{
1881+
VersionRange::allGTE(attr->Introduced.value())};
1882+
18801883
// Find the innermost enclosing declaration with an availability
18811884
// range annotation and ensure that this attribute's available version range
18821885
// is fully contained within that declaration's range. If there is no such
18831886
// enclosing declaration, then there is nothing to check.
18841887
Optional<AvailabilityContext> EnclosingAnnotatedRange;
1885-
bool EnclosingDeclIsUnavailable = false;
1886-
Decl *EnclosingDecl = getEnclosingDeclForDecl(D);
1887-
1888-
while (EnclosingDecl) {
1889-
if (EnclosingDecl->getAttrs().getUnavailable(Ctx)) {
1890-
EnclosingDeclIsUnavailable = true;
1891-
break;
1892-
}
1893-
1894-
EnclosingAnnotatedRange =
1895-
AvailabilityInference::annotatedAvailableRange(EnclosingDecl, Ctx);
1896-
1897-
if (EnclosingAnnotatedRange.has_value())
1898-
break;
18991888

1900-
EnclosingDecl = getEnclosingDeclForDecl(EnclosingDecl);
1901-
}
1902-
1903-
AvailabilityContext AttrRange{
1904-
VersionRange::allGTE(attr->Introduced.value())};
1905-
1906-
if (EnclosingDecl) {
1907-
if (EnclosingDeclIsUnavailable) {
1889+
if (auto *parent = getEnclosingDeclForDecl(D)) {
1890+
if (auto enclosingUnavailable = parent->getSemanticUnavailableAttr()) {
19081891
if (!AttrRange.isKnownUnreachable()) {
1909-
diagnose(D->isImplicit() ? EnclosingDecl->getLoc()
1892+
const Decl *enclosingDecl = enclosingUnavailable.value().second;
1893+
diagnose(D->isImplicit() ? enclosingDecl->getLoc()
19101894
: attr->getLocation(),
19111895
diag::availability_decl_more_than_unavailable_enclosing,
19121896
D->getDescriptiveKind());
1913-
diagnose(EnclosingDecl->getLoc(),
1897+
diagnose(parent->getLoc(),
19141898
diag::availability_decl_more_than_unavailable_enclosing_here);
19151899
}
1916-
} else if (!AttrRange.isContainedIn(EnclosingAnnotatedRange.value())) {
1917-
diagnose(D->isImplicit() ? EnclosingDecl->getLoc() : attr->getLocation(),
1918-
diag::availability_decl_more_than_enclosing,
1919-
D->getDescriptiveKind());
1920-
if (D->isImplicit())
1921-
diagnose(EnclosingDecl->getLoc(),
1922-
diag::availability_implicit_decl_here,
1923-
D->getDescriptiveKind(),
1900+
} else if (auto enclosingAvailable =
1901+
parent->getSemanticAvailableRangeAttr()) {
1902+
const AvailableAttr *enclosingAttr = enclosingAvailable.value().first;
1903+
const Decl *enclosingDecl = enclosingAvailable.value().second;
1904+
EnclosingAnnotatedRange.emplace(
1905+
VersionRange::allGTE(enclosingAttr->Introduced.value()));
1906+
if (!AttrRange.isContainedIn(*EnclosingAnnotatedRange)) {
1907+
// Members of extensions of nominal types with available ranges were
1908+
// not diagnosed previously, so only emit a warning in that case.
1909+
auto limit = (enclosingDecl != parent && isa<ExtensionDecl>(parent))
1910+
? DiagnosticBehavior::Warning
1911+
: DiagnosticBehavior::Unspecified;
1912+
diagnose(D->isImplicit() ? enclosingDecl->getLoc()
1913+
: attr->getLocation(),
1914+
diag::availability_decl_more_than_enclosing,
1915+
D->getDescriptiveKind())
1916+
.limitBehavior(limit);
1917+
if (D->isImplicit())
1918+
diagnose(enclosingDecl->getLoc(),
1919+
diag::availability_implicit_decl_here,
1920+
D->getDescriptiveKind(),
1921+
prettyPlatformString(targetPlatform(Ctx.LangOpts)),
1922+
AttrRange.getOSVersion().getLowerEndpoint());
1923+
diagnose(enclosingDecl->getLoc(),
1924+
diag::availability_decl_more_than_enclosing_here,
19241925
prettyPlatformString(targetPlatform(Ctx.LangOpts)),
1925-
AttrRange.getOSVersion().getLowerEndpoint());
1926-
diagnose(EnclosingDecl->getLoc(),
1927-
diag::availability_decl_more_than_enclosing_here,
1928-
prettyPlatformString(targetPlatform(Ctx.LangOpts)),
1929-
EnclosingAnnotatedRange->getOSVersion().getLowerEndpoint());
1926+
EnclosingAnnotatedRange->getOSVersion().getLowerEndpoint());
1927+
}
19301928
}
19311929
}
19321930

test/attr/attr_availability_osx.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ func doSomethingDeprecatedOniOS() { }
8080

8181
doSomethingDeprecatedOniOS() // okay
8282

83-
84-
struct TestStruct {}
83+
@available(macOS 10.10, *)
84+
struct TestStruct {} // expected-note {{enclosing scope requires availability of macOS 10.10 or newer}}
8585

8686
@available(macOS 10.10, *)
8787
extension TestStruct { // expected-note {{enclosing scope requires availability of macOS 10.10 or newer}}
@@ -104,6 +104,11 @@ extension TestStruct { // expected-note {{enclosing scope requires availability
104104
func doDeprecatedThing() {}
105105
}
106106

107+
extension TestStruct {
108+
@available(macOS 10.9, *) // expected-warning {{instance method cannot be more available than enclosing scope}}
109+
func doFifthThing() {}
110+
}
111+
107112
@available(macOS 10.11, *)
108113
func testMemberAvailability() {
109114
TestStruct().doTheThing() // expected-error {{'doTheThing()' is unavailable}}

test/attr/attr_inlinable_available.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public struct AtInliningTarget {
5555
}
5656

5757
@available(macOS 10.14.5, *)
58-
public struct BetweenTargets {
58+
public struct BetweenTargets { // expected-note {{enclosing scope requires availability of macOS 10.14.5 or newer}}
5959
@usableFromInline internal init() {}
6060
}
6161

@@ -1102,7 +1102,7 @@ extension BetweenTargets {
11021102
}
11031103

11041104
extension BetweenTargets {
1105-
@available(macOS 10.10, *)
1105+
@available(macOS 10.10, *) // expected-warning {{instance method cannot be more available than enclosing scope}}
11061106
func excessivelyAvailableInternalFuncInExtension() {}
11071107
}
11081108

0 commit comments

Comments
 (0)