mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Sema: Check access, availability, and exportability of availability domains.
Teach Sema to diagnose the access level, exportability, and availability of availability domains that are referenced by `@available` attributes and `if #available` statements. Resolves rdar://159147207.
This commit is contained in:
@@ -6989,6 +6989,17 @@ WARNING(attr_availability_expected_version_spec, none,
|
||||
ERROR(attr_availability_requires_custom_availability, none,
|
||||
"%0 requires '-enable-experimental-feature CustomAvailability'",
|
||||
(AvailabilityDomain))
|
||||
ERROR(attr_availability_domain_access, none,
|
||||
"availability domain '%0' is "
|
||||
"%select{private|fileprivate|internal|package|%error|%error}1 "
|
||||
"and cannot be used in '%2' on "
|
||||
"%select{private|fileprivate|internal|package|public|%error}3 %kind4",
|
||||
(AvailabilityDomain, AccessLevel, DeclAttribute, AccessLevel,
|
||||
const Decl *))
|
||||
ERROR(attr_availability_domain_not_usable_from_inline, none,
|
||||
"availability domain '%0' used in '%1' on %kind2 must be "
|
||||
"'@usableFromInline' or public",
|
||||
(AvailabilityDomain, DeclAttribute, const Decl *))
|
||||
|
||||
ERROR(availability_decl_unavailable, none,
|
||||
"%0 is unavailable%select{ in %2|}1%select{|: %3}3",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "swift/AST/Import.h"
|
||||
#include "swift/AST/ParameterList.h"
|
||||
#include "swift/AST/Pattern.h"
|
||||
#include "swift/AST/PrettyStackTrace.h"
|
||||
#include "swift/AST/TypeCheckRequests.h"
|
||||
#include "swift/Basic/Assertions.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
@@ -70,10 +71,22 @@ static void forAllRequirementTypes(
|
||||
using CheckTypeAccessCallback =
|
||||
void(AccessScope, const TypeRepr *, DowngradeToWarning, ImportAccessLevel);
|
||||
|
||||
using CheckDeclAccessCallback = void(AccessScope, SourceLoc, ImportAccessLevel);
|
||||
|
||||
class AccessControlCheckerBase {
|
||||
protected:
|
||||
bool checkUsableFromInline;
|
||||
|
||||
bool shouldSkipChecking(const ValueDecl *decl);
|
||||
|
||||
/// Returns true if access checking ought to be skipped for the given
|
||||
/// `AccessScope`.
|
||||
bool shouldSkipAccessCheckingInContext(AccessScope contextAccessScope,
|
||||
const ASTContext &ctx);
|
||||
|
||||
ImportAccessLevel getImportAccessForDecl(const ValueDecl *decl,
|
||||
const DeclContext *useDC);
|
||||
|
||||
void checkTypeAccessImpl(
|
||||
Type type, TypeRepr *typeRepr, AccessScope contextAccessScope,
|
||||
const DeclContext *useDC, bool mayBeInferred,
|
||||
@@ -102,6 +115,12 @@ protected:
|
||||
});
|
||||
}
|
||||
|
||||
void checkAvailabilityDomains(const Decl *D);
|
||||
|
||||
void checkDeclAccess(SourceLoc loc, const ValueDecl *decl,
|
||||
AccessScope contextAccessScope, const DeclContext *useDC,
|
||||
llvm::function_ref<CheckDeclAccessCallback> diagnose);
|
||||
|
||||
AccessControlCheckerBase(bool checkUsableFromInline)
|
||||
: checkUsableFromInline(checkUsableFromInline) {}
|
||||
|
||||
@@ -117,10 +136,50 @@ public:
|
||||
const ValueDecl *ownerDecl);
|
||||
|
||||
void checkGlobalActorAccess(const Decl *D);
|
||||
|
||||
void checkAvailabilityDomains(const Decl *D, AccessScope accessScope,
|
||||
AccessLevel contextAccess);
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
bool AccessControlCheckerBase::shouldSkipChecking(const ValueDecl *decl) {
|
||||
if (!checkUsableFromInline)
|
||||
return false;
|
||||
|
||||
if (decl->getFormalAccess() != AccessLevel::Internal &&
|
||||
decl->getFormalAccess() != AccessLevel::Package)
|
||||
return true;
|
||||
return !decl->isUsableFromInline();
|
||||
}
|
||||
|
||||
bool AccessControlCheckerBase::shouldSkipAccessCheckingInContext(
|
||||
AccessScope contextAccessScope, const ASTContext &ctx) {
|
||||
if (ctx.isAccessControlDisabled())
|
||||
return true;
|
||||
|
||||
// Don't spend time checking local declarations; this is always valid by the
|
||||
// time we get to this point.
|
||||
if (contextAccessScope.isInContext() &&
|
||||
contextAccessScope.getDeclContext()->isLocalContext())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ImportAccessLevel
|
||||
AccessControlCheckerBase::getImportAccessForDecl(const ValueDecl *decl,
|
||||
const DeclContext *useDC) {
|
||||
auto complainImport = decl->getImportAccessFrom(useDC);
|
||||
|
||||
// Don't complain about an import that doesn't restrict the access
|
||||
// level of the decl. This can happen with imported `package` decls.
|
||||
if (complainImport && complainImport->accessLevel >= decl->getFormalAccess())
|
||||
return std::nullopt;
|
||||
|
||||
return complainImport;
|
||||
}
|
||||
|
||||
/// Searches the given type representation for a `DeclRefTypeRepr` that is
|
||||
/// bound to a type declaration with the given access scope. The type
|
||||
/// representation is searched in source order. For example, nodes in
|
||||
@@ -201,12 +260,7 @@ void AccessControlCheckerBase::checkTypeAccessImpl(
|
||||
llvm::function_ref<CheckTypeAccessCallback> diagnose) {
|
||||
|
||||
auto &Context = useDC->getASTContext();
|
||||
if (Context.isAccessControlDisabled())
|
||||
return;
|
||||
// Don't spend time checking local declarations; this is always valid by the
|
||||
// time we get to this point.
|
||||
if (contextAccessScope.isInContext() &&
|
||||
contextAccessScope.getDeclContext()->isLocalContext())
|
||||
if (shouldSkipAccessCheckingInContext(contextAccessScope, Context))
|
||||
return;
|
||||
|
||||
// Report where it was imported from.
|
||||
@@ -229,7 +283,7 @@ void AccessControlCheckerBase::checkTypeAccessImpl(
|
||||
return TypeWalker::Action::Continue;
|
||||
}));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
AccessScope problematicAccessScope = AccessScope::getPublic();
|
||||
|
||||
@@ -307,19 +361,36 @@ void AccessControlCheckerBase::checkTypeAccessImpl(
|
||||
const ValueDecl *VD = complainRepr->getBoundDecl();
|
||||
assert(VD &&
|
||||
"findTypeDeclWithAccessScope should return bound TypeReprs only");
|
||||
complainImport = VD->getImportAccessFrom(useDC);
|
||||
|
||||
// Don't complain about an import that doesn't restrict the access
|
||||
// level of the decl. This can happen with imported `package` decls.
|
||||
if (complainImport.has_value() &&
|
||||
complainImport->accessLevel >= VD->getFormalAccess())
|
||||
complainImport = std::nullopt;
|
||||
complainImport = getImportAccessForDecl(VD, useDC);
|
||||
}
|
||||
|
||||
diagnose(problematicAccessScope, complainRepr, downgradeToWarning,
|
||||
complainImport);
|
||||
}
|
||||
|
||||
void AccessControlCheckerBase::checkDeclAccess(
|
||||
SourceLoc loc, const ValueDecl *decl, AccessScope contextAccessScope,
|
||||
const DeclContext *useDC,
|
||||
llvm::function_ref<CheckDeclAccessCallback> diagnose) {
|
||||
|
||||
auto &ctx = useDC->getASTContext();
|
||||
if (shouldSkipAccessCheckingInContext(contextAccessScope, ctx))
|
||||
return;
|
||||
|
||||
recordRequiredImportAccessLevelForDecl(
|
||||
decl, useDC, contextAccessScope.accessLevelForDiagnostics(), loc);
|
||||
|
||||
AccessScope declAccessScope =
|
||||
decl->getFormalAccessScope(useDC, checkUsableFromInline);
|
||||
if (contextAccessScope.hasEqualDeclContextWith(declAccessScope) ||
|
||||
contextAccessScope.isChildOf(declAccessScope))
|
||||
return;
|
||||
|
||||
// The reference to the decl violates the rules of access control.
|
||||
ImportAccessLevel complainImport = getImportAccessForDecl(decl, useDC);
|
||||
diagnose(declAccessScope, loc, complainImport);
|
||||
}
|
||||
|
||||
/// Checks if the access scope of the type described by \p TL is valid for the
|
||||
/// type to be the type of \p context. If it isn't, calls \p diagnose with a
|
||||
/// TypeRepr representing the offending part of \p TL.
|
||||
@@ -556,6 +627,50 @@ void AccessControlCheckerBase::checkGlobalActorAccess(const Decl *D) {
|
||||
});
|
||||
}
|
||||
|
||||
void AccessControlCheckerBase::checkAvailabilityDomains(
|
||||
const Decl *D, AccessScope accessScope, AccessLevel contextAccess) {
|
||||
auto &ctx = D->getASTContext();
|
||||
for (auto attr : D->getSemanticAvailableAttrs()) {
|
||||
if (auto *domainDecl = attr.getDomain().getDecl()) {
|
||||
checkDeclAccess(
|
||||
attr.getParsedAttr()->getDomainLoc(), domainDecl, accessScope,
|
||||
D->getDeclContext(),
|
||||
[&](AccessScope domainAccessScope, SourceLoc useLoc,
|
||||
ImportAccessLevel importLimit) {
|
||||
// FIXME: [availability] Improve diagnostics by indicating the decl
|
||||
// that the formal access is implied by. Enum cases, associated
|
||||
// types, protocol requirements, etc. inherit their access level
|
||||
// from their context.
|
||||
|
||||
if (checkUsableFromInline) {
|
||||
ctx.Diags.diagnose(
|
||||
useLoc, diag::attr_availability_domain_not_usable_from_inline,
|
||||
attr.getDomain(), attr.getParsedAttr(), D);
|
||||
noteLimitingImport(nullptr, ctx, importLimit, domainDecl);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.Diags.diagnose(useLoc, diag::attr_availability_domain_access,
|
||||
attr.getDomain(),
|
||||
domainAccessScope.accessLevelForDiagnostics(),
|
||||
attr.getParsedAttr(), contextAccess, D);
|
||||
noteLimitingImport(nullptr, ctx, importLimit, domainDecl);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AccessControlCheckerBase::checkAvailabilityDomains(const Decl *D) {
|
||||
auto VD = dyn_cast<ValueDecl>(D->getAbstractSyntaxDeclForAttributes());
|
||||
if (!VD || shouldSkipChecking(VD))
|
||||
return;
|
||||
|
||||
AccessScope contextAccessScope =
|
||||
VD->getFormalAccessScope(VD->getDeclContext(), checkUsableFromInline);
|
||||
|
||||
checkAvailabilityDomains(VD, contextAccessScope, VD->getFormalAccess());
|
||||
}
|
||||
|
||||
namespace {
|
||||
class AccessControlChecker : public AccessControlCheckerBase,
|
||||
public DeclVisitor<AccessControlChecker> {
|
||||
@@ -573,6 +688,7 @@ public:
|
||||
|
||||
DeclVisitor<AccessControlChecker>::visit(D);
|
||||
checkGlobalActorAccess(D);
|
||||
checkAvailabilityDomains(D);
|
||||
}
|
||||
|
||||
// Force all kinds to be handled at a lower level.
|
||||
@@ -1321,13 +1437,6 @@ public:
|
||||
UsableFromInlineChecker()
|
||||
: AccessControlCheckerBase(/*checkUsableFromInline=*/true) {}
|
||||
|
||||
static bool shouldSkipChecking(const ValueDecl *VD) {
|
||||
if (VD->getFormalAccess() != AccessLevel::Internal &&
|
||||
VD->getFormalAccess() != AccessLevel::Package)
|
||||
return true;
|
||||
return !VD->isUsableFromInline();
|
||||
};
|
||||
|
||||
void visit(Decl *D) {
|
||||
if (!D->getASTContext().isSwiftVersionAtLeast(4, 2))
|
||||
return;
|
||||
@@ -1341,6 +1450,7 @@ public:
|
||||
|
||||
DeclVisitor<UsableFromInlineChecker>::visit(D);
|
||||
checkGlobalActorAccess(D);
|
||||
checkAvailabilityDomains(D);
|
||||
}
|
||||
|
||||
// Force all kinds to be handled at a lower level.
|
||||
@@ -2139,10 +2249,22 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void checkAvailabilityDomains(const Decl *D) {
|
||||
D = D->getAbstractSyntaxDeclForAttributes();
|
||||
for (auto attr : D->getSemanticAvailableAttrs()) {
|
||||
if (auto *domainDecl = attr.getDomain().getDecl()) {
|
||||
diagnoseDeclAvailability(domainDecl,
|
||||
attr.getParsedAttr()->getDomainLoc(), nullptr,
|
||||
Where, std::nullopt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void visit(Decl *D) {
|
||||
DeclVisitor<DeclAvailabilityChecker>::visit(D);
|
||||
checkGlobalActor(D);
|
||||
checkAttachedMacros(D);
|
||||
checkAvailabilityDomains(D);
|
||||
}
|
||||
|
||||
// Force all kinds to be handled at a lower level.
|
||||
@@ -2372,14 +2494,10 @@ public:
|
||||
}
|
||||
|
||||
void checkConstrainedExtensionRequirements(ExtensionDecl *ED,
|
||||
bool hasExportedMembers) {
|
||||
ExportabilityReason reason) {
|
||||
if (!ED->getTrailingWhereClause())
|
||||
return;
|
||||
|
||||
ExportabilityReason reason =
|
||||
hasExportedMembers ? ExportabilityReason::ExtensionWithPublicMembers
|
||||
: ExportabilityReason::ExtensionWithConditionalConformances;
|
||||
|
||||
forAllRequirementTypes(ED, [&](Type type, TypeRepr *typeRepr) {
|
||||
checkType(type, typeRepr, ED, reason,
|
||||
DeclAvailabilityFlag::DisableUnsafeChecking);
|
||||
@@ -2423,7 +2541,23 @@ public:
|
||||
// the 'where' clause must only name exported types.
|
||||
Where = wasWhere.withExported(hasExportedMembers ||
|
||||
!ED->getInherited().empty());
|
||||
checkConstrainedExtensionRequirements(ED, hasExportedMembers);
|
||||
ExportabilityReason reason =
|
||||
hasExportedMembers
|
||||
? ExportabilityReason::ExtensionWithPublicMembers
|
||||
: ExportabilityReason::ExtensionWithConditionalConformances;
|
||||
checkConstrainedExtensionRequirements(ED, reason);
|
||||
|
||||
// Diagnose the exportability of the availability domains referenced by the
|
||||
// @available attributes attached to the extension.
|
||||
if (Where.isExported()) {
|
||||
for (auto availableAttr : ED->getSemanticAvailableAttrs()) {
|
||||
if (auto *domainDecl = availableAttr.getDomain().getDecl()) {
|
||||
TypeChecker::diagnoseDeclRefExportability(
|
||||
availableAttr.getParsedAttr()->getDomainLoc(), domainDecl,
|
||||
Where.withReason(reason));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we haven't already visited the extended nominal visit it here.
|
||||
// This logic is too wide but prevents false reports of an unused public
|
||||
@@ -2491,7 +2625,7 @@ public:
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
static void checkExtensionGenericParamAccess(const ExtensionDecl *ED) {
|
||||
static void checkExtensionAccess(const ExtensionDecl *ED) {
|
||||
auto *AA = ED->getAttrs().getAttribute<AccessControlAttr>();
|
||||
if (!AA)
|
||||
return;
|
||||
@@ -2522,8 +2656,11 @@ static void checkExtensionGenericParamAccess(const ExtensionDecl *ED) {
|
||||
break;
|
||||
}
|
||||
|
||||
AccessControlChecker().checkGenericParamAccess(
|
||||
ED, ED, desiredAccessScope, userSpecifiedAccess);
|
||||
auto accessChecker = AccessControlChecker();
|
||||
accessChecker.checkGenericParamAccess(ED, ED, desiredAccessScope,
|
||||
userSpecifiedAccess);
|
||||
accessChecker.checkAvailabilityDomains(ED, desiredAccessScope,
|
||||
userSpecifiedAccess);
|
||||
}
|
||||
|
||||
DisallowedOriginKind swift::getDisallowedOriginKind(const Decl *decl,
|
||||
@@ -2659,13 +2796,10 @@ void swift::checkAccessControl(Decl *D) {
|
||||
AccessControlChecker(allowInlineable).visit(D);
|
||||
UsableFromInlineChecker().visit(D);
|
||||
} else if (auto *ED = dyn_cast<ExtensionDecl>(D)) {
|
||||
checkExtensionGenericParamAccess(ED);
|
||||
checkExtensionAccess(ED);
|
||||
registerPackageAccessForPackageExtendedType(ED);
|
||||
}
|
||||
|
||||
if (isa<AccessorDecl>(D))
|
||||
return;
|
||||
|
||||
auto where = ExportContext::forDeclSignature(D);
|
||||
if (where.isImplicit())
|
||||
return;
|
||||
|
||||
@@ -563,6 +563,9 @@ void AttributeChecker::visitSensitiveAttr(SensitiveAttr *attr) {
|
||||
}
|
||||
|
||||
void AttributeChecker::visitTransparentAttr(TransparentAttr *attr) {
|
||||
if (attr->isImplicit())
|
||||
return;
|
||||
|
||||
DeclContext *dc = D->getDeclContext();
|
||||
// Protocol declarations cannot be transparent.
|
||||
if (isa<ProtocolDecl>(dc))
|
||||
|
||||
@@ -3719,11 +3719,11 @@ public:
|
||||
TypeChecker::checkProtocolSelfRequirements(FD);
|
||||
}
|
||||
|
||||
checkAccessControl(FD);
|
||||
|
||||
TypeChecker::checkParameterList(FD->getParameters(), FD);
|
||||
}
|
||||
|
||||
checkAccessControl(FD);
|
||||
|
||||
TypeChecker::checkDeclAttributes(FD);
|
||||
TypeChecker::checkDistributedFunc(FD);
|
||||
|
||||
|
||||
@@ -0,0 +1,328 @@
|
||||
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify \
|
||||
// RUN: -import-objc-header %S/Inputs/availability_domains_bridging_header.h \
|
||||
// RUN: -I %S/../Inputs/custom-modules/availability-domains \
|
||||
// RUN: -enable-experimental-feature CustomAvailability \
|
||||
// RUN: -experimental-spi-only-imports -parse-as-library -swift-version 4 \
|
||||
// RUN: %s
|
||||
|
||||
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify \
|
||||
// RUN: -import-objc-header %S/Inputs/availability_domains_bridging_header.h \
|
||||
// RUN: -I %S/../Inputs/custom-modules/availability-domains \
|
||||
// RUN: -enable-experimental-feature CustomAvailability \
|
||||
// RUN: -experimental-spi-only-imports -parse-as-library -swift-version 5 \
|
||||
// RUN: %s -verify-additional-prefix swift5-
|
||||
|
||||
// REQUIRES: swift_feature_CustomAvailability
|
||||
|
||||
private import Rivers // also re-exported by Oceans
|
||||
internal import Oceans
|
||||
// expected-note@-1 22 {{availability domain 'Arctic' imported as 'internal' from 'Oceans' here}}
|
||||
// expected-swift5-note@-2 2 {{availability domain 'Arctic' imported as 'internal' from 'Oceans' here}}
|
||||
// expected-note@-3 23 {{availability domain 'Colorado' imported as 'internal' from 'Oceans' here}}
|
||||
// expected-swift5-note@-4 2 {{availability domain 'Colorado' imported as 'internal' from 'Oceans' here}}
|
||||
// expected-note@-5 22 {{availability domain 'Grand' imported as 'internal' from 'Oceans' here}}
|
||||
// expected-swift5-note@-6 2 {{availability domain 'Grand' imported as 'internal' from 'Oceans' here}}
|
||||
public import Seas
|
||||
@_spiOnly import Lakes
|
||||
|
||||
@available(Colorado) // expected-error {{availability domain 'Colorado' is internal and cannot be used in '@available' on public global function 'publicFunc()'}}
|
||||
@available(Grand) // expected-error {{availability domain 'Grand' is internal and cannot be used in '@available' on public global function 'publicFunc()'}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-error {{availability domain 'Arctic' is internal and cannot be used in '@available' on public global function 'publicFunc()'}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt) // expected-error {{cannot use availability domain 'Salt' here; 'Lakes' was imported for SPI only}}
|
||||
public func publicFunc() { }
|
||||
|
||||
@available(Colorado) // expected-swift5-error {{availability domain 'Colorado' used in '@available' on global function 'usableFromInlineFunc()' must be '@usableFromInline' or public}}
|
||||
@available(Grand) // expected-swift5-error {{availability domain 'Grand' used in '@available' on global function 'usableFromInlineFunc()' must be '@usableFromInline' or public}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-swift5-error {{availability domain 'Arctic' used in '@available' on global function 'usableFromInlineFunc()' must be '@usableFromInline' or public}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt) // expected-error {{cannot use availability domain 'Salt' here; 'Lakes' was imported for SPI only}}
|
||||
@usableFromInline func usableFromInlineFunc() { }
|
||||
|
||||
@available(Colorado) // expected-error {{availability domain 'Colorado' is internal and cannot be used in '@available' on public global function 'spiFunc()'}}
|
||||
@available(Grand) // expected-error {{availability domain 'Grand' is internal and cannot be used in '@available' on public global function 'spiFunc()'}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-error {{availability domain 'Arctic' is internal and cannot be used in '@available' on public global function 'spiFunc()'}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt)
|
||||
@_spi(Private) public func spiFunc() { }
|
||||
|
||||
@available(Colorado)
|
||||
@available(Grand) // expected-warning {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic)
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt)
|
||||
func internalFunc() { }
|
||||
|
||||
@available(Colorado)
|
||||
@available(Grand) // expected-warning {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic)
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt)
|
||||
private func privateFunc() { }
|
||||
|
||||
@available(Colorado) // expected-error {{availability domain 'Colorado' is internal and cannot be used in '@available' on public var 'publicGlobalVar'}}
|
||||
@available(Grand) // expected-error {{availability domain 'Grand' is internal and cannot be used in '@available' on public var 'publicGlobalVar'}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-error {{availability domain 'Arctic' is internal and cannot be used in '@available' on public var 'publicGlobalVar'}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt) // expected-error {{cannot use availability domain 'Salt' here; 'Lakes' was imported for SPI only}}
|
||||
public var publicGlobalVar: Int {
|
||||
get { 0 }
|
||||
set { }
|
||||
}
|
||||
|
||||
@available(Colorado) // expected-error {{availability domain 'Colorado' is internal and cannot be used in '@available' on public struct 'PublicStruct'}}
|
||||
@available(Grand) // expected-error {{availability domain 'Grand' is internal and cannot be used in '@available' on public struct 'PublicStruct'}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-error {{availability domain 'Arctic' is internal and cannot be used in '@available' on public struct 'PublicStruct'}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt) // expected-error {{cannot use availability domain 'Salt' here; 'Lakes' was imported for SPI only}}
|
||||
public struct PublicStruct { }
|
||||
|
||||
public struct PublicGenericStruct<T> {
|
||||
var value: T
|
||||
|
||||
@available(Colorado) // expected-error {{availability domain 'Colorado' is internal and cannot be used in '@available' on public initializer 'init(value:)'}}
|
||||
@available(Grand) // expected-error {{availability domain 'Grand' is internal and cannot be used in '@available' on public initializer 'init(value:)'}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-error {{availability domain 'Arctic' is internal and cannot be used in '@available' on public initializer 'init(value:)'}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt) // expected-error {{cannot use availability domain 'Salt' here; 'Lakes' was imported for SPI only}}
|
||||
public init(value: T) {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
@available(Colorado) // expected-error {{availability domain 'Colorado' is internal and cannot be used in '@available' on public property 'publicProperty'}}
|
||||
@available(Grand) // expected-error {{availability domain 'Grand' is internal and cannot be used in '@available' on public property 'publicProperty'}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-error {{availability domain 'Arctic' is internal and cannot be used in '@available' on public property 'publicProperty'}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt) // expected-error {{cannot use availability domain 'Salt' here; 'Lakes' was imported for SPI only}}
|
||||
public var publicProperty: T { value }
|
||||
|
||||
@available(Colorado) // expected-swift5-error {{availability domain 'Colorado' used in '@available' on property 'usableFromInlineProperty' must be '@usableFromInline' or public}}
|
||||
@available(Grand) // expected-swift5-error {{availability domain 'Grand' used in '@available' on property 'usableFromInlineProperty' must be '@usableFromInline' or public}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-swift5-error {{availability domain 'Arctic' used in '@available' on property 'usableFromInlineProperty' must be '@usableFromInline' or public}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt) // expected-error {{cannot use availability domain 'Salt' here; 'Lakes' was imported for SPI only}}
|
||||
@usableFromInline var usableFromInlineProperty: T { value }
|
||||
|
||||
public var publicPropertyWithSetter: T {
|
||||
get { value }
|
||||
|
||||
@available(Colorado) // expected-error {{availability domain 'Colorado' is internal and cannot be used in '@available' on public setter for property 'publicPropertyWithSetter'}}
|
||||
@available(Grand) // expected-error {{availability domain 'Grand' is internal and cannot be used in '@available' on public setter for property 'publicPropertyWithSetter'}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-error {{availability domain 'Arctic' is internal and cannot be used in '@available' on public setter for property 'publicPropertyWithSetter'}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt) // expected-error {{cannot use availability domain 'Salt' here; 'Lakes' was imported for SPI only}}
|
||||
set { value = newValue }
|
||||
}
|
||||
|
||||
@available(Colorado) // expected-error {{availability domain 'Colorado' is internal and cannot be used in '@available' on public instance method 'publicMethod()'}}
|
||||
@available(Grand) // expected-error {{availability domain 'Grand' is internal and cannot be used in '@available' on public instance method 'publicMethod()'}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-error {{availability domain 'Arctic' is internal and cannot be used in '@available' on public instance method 'publicMethod()'}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt) // expected-error {{cannot use availability domain 'Salt' here; 'Lakes' was imported for SPI only}}
|
||||
public func publicMethod() { }
|
||||
|
||||
@available(Colorado) // expected-error {{availability domain 'Colorado' is internal and cannot be used in '@available' on public subscript 'subscript(_:)'}}
|
||||
@available(Colorado) // expected-error {{availability domain 'Colorado' is internal and cannot be used in '@available' on public subscript 'subscript(_:)'}}
|
||||
@available(Grand) // expected-error {{availability domain 'Grand' is internal and cannot be used in '@available' on public subscript 'subscript(_:)'}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-error {{availability domain 'Arctic' is internal and cannot be used in '@available' on public subscript 'subscript(_:)'}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt) // expected-error {{cannot use availability domain 'Salt' here; 'Lakes' was imported for SPI only}}
|
||||
public subscript(indexForSubscriptInColorado: T) -> T { value }
|
||||
}
|
||||
|
||||
@available(Colorado) // expected-error {{availability domain 'Colorado' is internal and cannot be used in '@available' on public enum 'PublicEnum'}}
|
||||
@available(Grand) // expected-error {{availability domain 'Grand' is internal and cannot be used in '@available' on public enum 'PublicEnum'}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-error {{availability domain 'Arctic' is internal and cannot be used in '@available' on public enum 'PublicEnum'}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt) // expected-error {{cannot use availability domain 'Salt' here; 'Lakes' was imported for SPI only}}
|
||||
public enum PublicEnum { }
|
||||
|
||||
public enum PublicEnumWithCase {
|
||||
@available(Colorado) // expected-error {{availability domain 'Colorado' is internal and cannot be used in '@available' on public enum case 'colorado'}}
|
||||
@available(Grand) // expected-error {{availability domain 'Grand' is internal and cannot be used in '@available' on public enum case 'colorado'}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-error {{availability domain 'Arctic' is internal and cannot be used in '@available' on public enum case 'colorado'}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt) // expected-error {{cannot use availability domain 'Salt' here; 'Lakes' was imported for SPI only}}
|
||||
case colorado
|
||||
}
|
||||
|
||||
@available(Colorado) // expected-error {{availability domain 'Colorado' is internal and cannot be used in '@available' on public class 'PublicClass'}}
|
||||
@available(Grand) // expected-error {{availability domain 'Grand' is internal and cannot be used in '@available' on public class 'PublicClass'}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-error {{availability domain 'Arctic' is internal and cannot be used in '@available' on public class 'PublicClass'}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt) // expected-error {{cannot use availability domain 'Salt' here; 'Lakes' was imported for SPI only}}
|
||||
public class PublicClass { }
|
||||
|
||||
@available(Colorado) // expected-error {{availability domain 'Colorado' is internal and cannot be used in '@available' on public protocol 'PublicProtocol'}}
|
||||
@available(Grand) // expected-error {{availability domain 'Grand' is internal and cannot be used in '@available' on public protocol 'PublicProtocol'}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-error {{availability domain 'Arctic' is internal and cannot be used in '@available' on public protocol 'PublicProtocol'}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt) // expected-error {{cannot use availability domain 'Salt' here; 'Lakes' was imported for SPI only}}
|
||||
public protocol PublicProtocol { }
|
||||
|
||||
public protocol PublicProtocolWithAssociatedType {
|
||||
@available(Colorado) // expected-error {{availability domain 'Colorado' is internal and cannot be used in '@available' on public associated type 'AssociatedType'}}
|
||||
@available(Grand) // expected-error {{availability domain 'Grand' is internal and cannot be used in '@available' on public associated type 'AssociatedType'}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-error {{availability domain 'Arctic' is internal and cannot be used in '@available' on public associated type 'AssociatedType'}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt) // expected-error {{cannot use availability domain 'Salt' here; 'Lakes' was imported for SPI only}}
|
||||
associatedtype AssociatedType
|
||||
|
||||
@available(Colorado) // expected-error {{availability domain 'Colorado' is internal and cannot be used in '@available' on public instance method 'requirement()'}}
|
||||
@available(Grand) // expected-error {{availability domain 'Grand' is internal and cannot be used in '@available' on public instance method 'requirement()'}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-error {{availability domain 'Arctic' is internal and cannot be used in '@available' on public instance method 'requirement()'}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt) // expected-error {{cannot use availability domain 'Salt' here; 'Lakes' was imported for SPI only}}
|
||||
func requirement() -> AssociatedType
|
||||
}
|
||||
|
||||
@available(Colorado) // expected-error {{availability domain 'Colorado' is internal and cannot be used in '@available' on public type alias 'PublicTypealias'}}
|
||||
@available(Grand) // expected-error {{availability domain 'Grand' is internal and cannot be used in '@available' on public type alias 'PublicTypealias'}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-error {{availability domain 'Arctic' is internal and cannot be used in '@available' on public type alias 'PublicTypealias'}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt) // expected-error {{cannot use availability domain 'Salt' here; 'Lakes' was imported for SPI only}}
|
||||
public typealias PublicTypealias = Int
|
||||
|
||||
@available(Colorado)
|
||||
@available(Grand) // expected-warning {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic)
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt)
|
||||
extension PublicGenericStruct { }
|
||||
|
||||
@available(Colorado) // expected-error {{availability domain 'Colorado' is internal and cannot be used in '@available' on public extension of generic struct 'PublicGenericStruct'}}
|
||||
@available(Grand) // expected-error {{availability domain 'Grand' is internal and cannot be used in '@available' on public extension of generic struct 'PublicGenericStruct'}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-error {{availability domain 'Arctic' is internal and cannot be used in '@available' on public extension of generic struct 'PublicGenericStruct'}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt) // FIXME: Should be diangosed
|
||||
public extension PublicGenericStruct { }
|
||||
|
||||
@available(Colorado)
|
||||
@available(Grand) // expected-warning {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic)
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt)
|
||||
extension PublicGenericStruct {
|
||||
func internalMethodInExtensionInColorado() { }
|
||||
}
|
||||
|
||||
@available(Colorado) // expected-error {{cannot use availability domain 'Colorado' in an extension with public or '@usableFromInline' members; 'Rivers' was not imported publicly}}
|
||||
@available(Grand) // expected-error {{cannot use availability domain 'Grand' in an extension with public or '@usableFromInline' members; 'Rivers' was not imported publicly}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-error {{cannot use availability domain 'Arctic' in an extension with public or '@usableFromInline' members; 'Oceans' was not imported publicly}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
// FIXME: Duplicate error
|
||||
@available(Salt) // expected-error {{cannot use availability domain 'Salt' here; 'Lakes' was imported for SPI only}}
|
||||
// expected-error@-1 {{cannot use availability domain 'Salt' in an extension with public or '@usableFromInline' members; 'Lakes' was imported for SPI only}}
|
||||
extension PublicGenericStruct {
|
||||
public func publicMethodInExtensionInColorado() { }
|
||||
}
|
||||
|
||||
@available(Colorado)
|
||||
@available(Grand) // expected-warning {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic)
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt)
|
||||
extension PublicGenericStruct where T: PublicProtocolWithAssociatedType { }
|
||||
|
||||
@available(Colorado) // expected-error {{cannot use availability domain 'Colorado' in an extension with conditional conformances; 'Rivers' was not imported publicly}}
|
||||
@available(Grand) // expected-error {{cannot use availability domain 'Grand' in an extension with conditional conformances; 'Rivers' was not imported publicly}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-error {{cannot use availability domain 'Arctic' in an extension with conditional conformances; 'Oceans' was not imported publicly}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
// FIXME: Duplicate error
|
||||
@available(Salt) // expected-error {{cannot use availability domain 'Salt' in an extension with conditional conformances; 'Lakes' was imported for SPI only}}
|
||||
// expected-error@-1 {{cannot use availability domain 'Salt' here; 'Lakes' was imported for SPI only}}
|
||||
extension PublicGenericStruct: PublicProtocol {}
|
||||
|
||||
@available(Colorado) // expected-error {{cannot use availability domain 'Colorado' in an extension with public or '@usableFromInline' members; 'Rivers' was not imported publicly}}
|
||||
@available(Grand) // expected-error {{cannot use availability domain 'Grand' in an extension with public or '@usableFromInline' members; 'Rivers' was not imported publicly}}
|
||||
// expected-warning@-1 {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic) // expected-error {{cannot use availability domain 'Arctic' in an extension with public or '@usableFromInline' members; 'Oceans' was not imported publicly}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
// FIXME: Duplicate error
|
||||
@available(Salt) // expected-error {{cannot use availability domain 'Salt' here; 'Lakes' was imported for SPI only}}
|
||||
// expected-error@-1 {{cannot use availability domain 'Salt' in an extension with public or '@usableFromInline' members; 'Lakes' was imported for SPI only}}
|
||||
extension PublicGenericStruct: PublicProtocolWithAssociatedType {
|
||||
public func requirement() -> Int { 0 }
|
||||
}
|
||||
|
||||
@inlinable public func inlinableFunc() {
|
||||
if #available(Colorado) { } // expected-error {{availability domain 'Colorado' is internal and cannot be referenced from an '@inlinable' function}}
|
||||
if #available(Grand) { } // expected-error {{availability domain 'Grand' is internal and cannot be referenced from an '@inlinable' function}}
|
||||
if #available(Arctic) { } // expected-error {{availability domain 'Arctic' is internal and cannot be referenced from an '@inlinable' function}}
|
||||
if #available(Baltic) { }
|
||||
if #available(BayBridge) { }
|
||||
if #available(Salt) { } // expected-error {{availability domain 'Salt' cannot be used in an '@inlinable' function because 'Lakes' was imported for SPI only}}
|
||||
|
||||
@available(Colorado) // expected-error {{availability domain 'Colorado' is internal and cannot be referenced from an '@inlinable' function}}
|
||||
@available(Grand) // expected-error {{availability domain 'Grand' is internal and cannot be referenced from an '@inlinable' function}}
|
||||
@available(Arctic) // expected-error {{availability domain 'Arctic' is internal and cannot be referenced from an '@inlinable' function}}
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt) // expected-error {{availability domain 'Salt' cannot be used in an '@inlinable' function because 'Lakes' was imported for SPI only}}
|
||||
func nestedFunc() { }
|
||||
}
|
||||
|
||||
public func nonInlinablePublicFunc() {
|
||||
if #available(Colorado) { }
|
||||
if #available(Grand) { } // expected-warning {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
if #available(Arctic) { }
|
||||
if #available(Baltic) { }
|
||||
if #available(BayBridge) { }
|
||||
if #available(Salt) { }
|
||||
|
||||
@available(Colorado)
|
||||
@available(Grand) // expected-warning {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
@available(Arctic)
|
||||
@available(Baltic)
|
||||
@available(BayBridge)
|
||||
@available(Salt)
|
||||
func nestedFunc() { }
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify \
|
||||
// RUN: -import-objc-header %S/Inputs/availability_domains_bridging_header.h \
|
||||
// RUN: -I %S/../Inputs/custom-modules/availability-domains \
|
||||
// RUN: -enable-experimental-feature CustomAvailability \
|
||||
// RUN: %s
|
||||
|
||||
// REQUIRES: swift_feature_CustomAvailability
|
||||
|
||||
private import Rivers // also re-exported by Oceans
|
||||
internal import Oceans
|
||||
// expected-note@-1 {{availability domain 'Arctic' imported as 'internal' from 'Oceans' here}}
|
||||
// expected-note@-2 {{availability domain 'Colorado' imported as 'internal' from 'Oceans' here}}
|
||||
// expected-note@-3 {{availability domain 'Grand' imported as 'internal' from 'Oceans' here}}
|
||||
public import Seas
|
||||
|
||||
@inlinable public func inlinableFunc() {
|
||||
if #available(Colorado) { } // expected-error {{availability domain 'Colorado' is internal and cannot be referenced from an '@inlinable' function}}
|
||||
if #available(Grand) { } // expected-error {{availability domain 'Grand' is internal and cannot be referenced from an '@inlinable' function}}
|
||||
if #available(Arctic) { } // expected-error {{availability domain 'Arctic' is internal and cannot be referenced from an '@inlinable' function}}
|
||||
if #available(Baltic) { }
|
||||
if #available(BayBridge) { }
|
||||
}
|
||||
|
||||
public func nonInlinablePublicFunc() {
|
||||
if #available(Colorado) { }
|
||||
if #available(Grand) { } // expected-warning {{availability domain 'Grand' is deprecated: Use Colorado instead}}
|
||||
if #available(Arctic) { }
|
||||
if #available(Baltic) { }
|
||||
if #available(BayBridge) { }
|
||||
}
|
||||
13
test/Inputs/custom-modules/availability-domains/Lakes.h
Normal file
13
test/Inputs/custom-modules/availability-domains/Lakes.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#include <feature-availability.h>
|
||||
|
||||
static struct __AvailabilityDomain salt_domain __attribute__((
|
||||
availability_domain(Salt))) = {__AVAILABILITY_DOMAIN_ENABLED, 0};
|
||||
|
||||
#define AVAIL 0
|
||||
#define UNAVAIL 1
|
||||
|
||||
__attribute__((availability(domain:Salt, AVAIL)))
|
||||
void available_in_salt(void);
|
||||
|
||||
#undef UNAVAIL
|
||||
#undef AVAIL
|
||||
@@ -12,3 +12,8 @@ module Seas {
|
||||
header "Seas.h"
|
||||
export *
|
||||
}
|
||||
|
||||
module Lakes {
|
||||
header "Lakes.h"
|
||||
export *
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user