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:
Allan Shortlidge
2025-08-25 15:59:34 -07:00
parent 9de88624b2
commit 7ac68cecb1
8 changed files with 530 additions and 66 deletions

View File

@@ -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",

View File

@@ -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;

View File

@@ -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))

View File

@@ -3719,11 +3719,11 @@ public:
TypeChecker::checkProtocolSelfRequirements(FD);
}
checkAccessControl(FD);
TypeChecker::checkParameterList(FD->getParameters(), FD);
}
checkAccessControl(FD);
TypeChecker::checkDeclAttributes(FD);
TypeChecker::checkDistributedFunc(FD);

View File

@@ -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() { }
}

View File

@@ -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) { }
}

View 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

View File

@@ -12,3 +12,8 @@ module Seas {
header "Seas.h"
export *
}
module Lakes {
header "Lakes.h"
export *
}