Skip to content

Commit 9de8862

Browse files
committed
Sema: Diagnose availability of availability domains in if #available queries.
When emitting statement diagnostics for `if #available` queries, diagnose the availability of the decls representing the referenced availability domains. Among other things, this checks that the domains are sufficiently visible to be used in the containing function body context.
1 parent 6c1a977 commit 9de8862

File tree

5 files changed

+56
-3
lines changed

5 files changed

+56
-3
lines changed

lib/AST/AvailabilityDomain.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,7 @@ getCustomDomainKind(clang::FeatureAvailKind featureAvailKind) {
4141
static const CustomAvailabilityDomain *
4242
customDomainForClangDecl(ValueDecl *decl) {
4343
auto *clangDecl = decl->getClangDecl();
44-
ASSERT(clangDecl);
45-
46-
auto *varDecl = dyn_cast<clang::VarDecl>(clangDecl);
44+
auto *varDecl = dyn_cast_or_null<clang::VarDecl>(clangDecl);
4745
if (!varDecl)
4846
return nullptr;
4947

lib/AST/DiagnosticEngine.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
//===----------------------------------------------------------------------===//
1717

1818
#include "swift/AST/DiagnosticEngine.h"
19+
#include "swift/AST/AvailabilityDomain.h"
1920
#include "swift/AST/ASTContext.h"
2021
#include "swift/AST/ASTPrinter.h"
2122
#include "swift/AST/Decl.h"
@@ -877,6 +878,20 @@ static void formatDiagnosticArgument(StringRef Modifier,
877878
assert(Modifier.empty() && "Improper modifier for ValueDecl argument");
878879
}
879880

881+
// Handle declarations representing an AvailabilityDomain specially.
882+
if (auto VD = dyn_cast<ValueDecl>(D)) {
883+
if (auto domain = AvailabilityDomain::forCustom(const_cast<ValueDecl *>(VD))) {
884+
Out << "availability domain";
885+
886+
if (includeName) {
887+
Out << " " << FormatOpts.OpeningQuotationMark;
888+
Out << domain->getNameForDiagnostics();
889+
Out << FormatOpts.ClosingQuotationMark;
890+
}
891+
break;
892+
}
893+
}
894+
880895
if (includeName) {
881896
if (auto accessor = dyn_cast<AccessorDecl>(D)) {
882897
// If it's an accessor, describe that and then switch to discussing its

lib/Sema/MiscDiagnostics.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5257,6 +5257,12 @@ static bool diagnoseAvailabilityCondition(PoundAvailableInfo *info,
52575257
return true;
52585258
}
52595259

5260+
// Check the availability of the domain decl.
5261+
if (auto *domainDecl = spec.getDomain().getDecl()) {
5262+
auto where = ExportContext::forFunctionBody(DC, loc);
5263+
diagnoseDeclAvailability(domainDecl, loc, nullptr, where);
5264+
}
5265+
52605266
hasValidSpecs = true;
52615267
if (!domain.isPlatform())
52625268
allValidSpecsArePlatform = false;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify \
2+
// RUN: -import-objc-header %S/Inputs/availability_domains_bridging_header.h \
3+
// RUN: -I %S/../Inputs/custom-modules/availability-domains \
4+
// RUN: -enable-experimental-feature CustomAvailability \
5+
// RUN: %s
6+
7+
// REQUIRES: swift_feature_CustomAvailability
8+
9+
private import Rivers // also re-exported by Oceans
10+
internal import Oceans
11+
// expected-note@-1 {{availability domain 'Arctic' imported as 'internal' from 'Oceans' here}}
12+
// expected-note@-2 {{availability domain 'Colorado' imported as 'internal' from 'Oceans' here}}
13+
// expected-note@-3 {{availability domain 'Grand' imported as 'internal' from 'Oceans' here}}
14+
public import Seas
15+
16+
@inlinable public func inlinableFunc() {
17+
if #available(Colorado) { } // expected-error {{availability domain 'Colorado' is internal and cannot be referenced from an '@inlinable' function}}
18+
if #available(Grand) { } // expected-error {{availability domain 'Grand' is internal and cannot be referenced from an '@inlinable' function}}
19+
if #available(Arctic) { } // expected-error {{availability domain 'Arctic' is internal and cannot be referenced from an '@inlinable' function}}
20+
if #available(Baltic) { }
21+
if #available(BayBridge) { }
22+
}
23+
24+
public func nonInlinablePublicFunc() {
25+
if #available(Colorado) { }
26+
if #available(Grand) { } // expected-warning {{availability domain 'Grand' is deprecated: Use Colorado instead}}
27+
if #available(Arctic) { }
28+
if #available(Baltic) { }
29+
if #available(BayBridge) { }
30+
}

test/Inputs/custom-modules/availability-domains/Rivers.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
static struct __AvailabilityDomain colorado_domain __attribute__((
44
availability_domain(Colorado))) = {__AVAILABILITY_DOMAIN_DISABLED, 0};
55

6+
__attribute__((deprecated("Use Colorado instead")))
7+
static struct __AvailabilityDomain grand_domain __attribute__((
8+
availability_domain(Grand))) = {__AVAILABILITY_DOMAIN_DISABLED, 0};
9+
610
#define AVAIL 0
711
#define UNAVAIL 1
812

0 commit comments

Comments
 (0)