diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 54310001bb7c3..8b04951853c6a 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -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", diff --git a/lib/AST/AvailabilityDomain.cpp b/lib/AST/AvailabilityDomain.cpp index db245ac22f9b2..f4329774b73da 100644 --- a/lib/AST/AvailabilityDomain.cpp +++ b/lib/AST/AvailabilityDomain.cpp @@ -41,9 +41,7 @@ getCustomDomainKind(clang::FeatureAvailKind featureAvailKind) { static const CustomAvailabilityDomain * customDomainForClangDecl(ValueDecl *decl) { auto *clangDecl = decl->getClangDecl(); - ASSERT(clangDecl); - - auto *varDecl = dyn_cast(clangDecl); + auto *varDecl = dyn_cast_or_null(clangDecl); if (!varDecl) return nullptr; diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index a26d6eafec562..00daeba9490bc 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -16,6 +16,7 @@ //===----------------------------------------------------------------------===// #include "swift/AST/DiagnosticEngine.h" +#include "swift/AST/AvailabilityDomain.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ASTPrinter.h" #include "swift/AST/Decl.h" @@ -877,6 +878,20 @@ static void formatDiagnosticArgument(StringRef Modifier, assert(Modifier.empty() && "Improper modifier for ValueDecl argument"); } + // Handle declarations representing an AvailabilityDomain specially. + if (auto VD = dyn_cast(D)) { + if (auto domain = AvailabilityDomain::forCustom(const_cast(VD))) { + Out << "availability domain"; + + if (includeName) { + Out << " " << FormatOpts.OpeningQuotationMark; + Out << domain->getNameForDiagnostics(); + Out << FormatOpts.ClosingQuotationMark; + } + break; + } + } + if (includeName) { if (auto accessor = dyn_cast(D)) { // If it's an accessor, describe that and then switch to discussing its diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index 368f753388b0b..460f489995a4c 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -5257,6 +5257,12 @@ static bool diagnoseAvailabilityCondition(PoundAvailableInfo *info, return true; } + // Check the availability of the domain decl. + if (auto *domainDecl = spec.getDomain().getDecl()) { + auto where = ExportContext::forFunctionBody(DC, loc); + diagnoseDeclAvailability(domainDecl, loc, nullptr, where); + } + hasValidSpecs = true; if (!domain.isPlatform()) allValidSpecsArePlatform = false; diff --git a/lib/Sema/TypeCheckAccess.cpp b/lib/Sema/TypeCheckAccess.cpp index b1aae3a489466..bafb1de01e054 100644 --- a/lib/Sema/TypeCheckAccess.cpp +++ b/lib/Sema/TypeCheckAccess.cpp @@ -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 @@ class AccessControlCheckerBase { }); } + void checkAvailabilityDomains(const Decl *D); + + void checkDeclAccess(SourceLoc loc, const ValueDecl *decl, + AccessScope contextAccessScope, const DeclContext *useDC, + llvm::function_ref diagnose); + AccessControlCheckerBase(bool checkUsableFromInline) : checkUsableFromInline(checkUsableFromInline) {} @@ -117,10 +136,50 @@ class AccessControlCheckerBase { 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 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 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(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 { @@ -573,7 +688,7 @@ class AccessControlChecker : public AccessControlCheckerBase, DeclVisitor::visit(D); checkGlobalActorAccess(D); - checkAttachedMacrosAccess(D); + checkAvailabilityDomains(D); } // Force all kinds to be handled at a lower level. @@ -1314,19 +1429,6 @@ class AccessControlChecker : public AccessControlCheckerBase, noteLimitingImport(MD, minImportLimit, complainRepr); } } - - void checkAttachedMacrosAccess(const Decl *D) { - for (auto customAttrC : D->getExpandedAttrs().getAttributes()) { - auto customAttr = const_cast(customAttrC); - auto *macroDecl = D->getResolvedMacro(customAttr); - if (macroDecl) { - diagnoseDeclAvailability( - macroDecl, customAttr->getTypeRepr()->getSourceRange(), nullptr, - ExportContext::forDeclSignature(const_cast(D)), - std::nullopt); - } - } - } }; class UsableFromInlineChecker : public AccessControlCheckerBase, @@ -1335,13 +1437,6 @@ class UsableFromInlineChecker : public AccessControlCheckerBase, 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; @@ -1355,6 +1450,7 @@ class UsableFromInlineChecker : public AccessControlCheckerBase, DeclVisitor::visit(D); checkGlobalActorAccess(D); + checkAvailabilityDomains(D); } // Force all kinds to be handled at a lower level. @@ -2141,9 +2237,34 @@ class DeclAvailabilityChecker : public DeclVisitor { checkType(customAttr->getType(), customAttr->getTypeRepr(), D); } + void checkAttachedMacros(const Decl *D) { + for (auto customAttrC : D->getExpandedAttrs().getAttributes()) { + auto customAttr = const_cast(customAttrC); + auto *macroDecl = D->getResolvedMacro(customAttr); + if (macroDecl) { + diagnoseDeclAvailability(macroDecl, + customAttr->getTypeRepr()->getSourceRange(), + nullptr, Where, std::nullopt); + } + } + } + + 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::visit(D); checkGlobalActor(D); + checkAttachedMacros(D); + checkAvailabilityDomains(D); } // Force all kinds to be handled at a lower level. @@ -2373,14 +2494,10 @@ class DeclAvailabilityChecker : public DeclVisitor { } 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); @@ -2424,7 +2541,23 @@ class DeclAvailabilityChecker : public DeclVisitor { // 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 @@ -2492,7 +2625,7 @@ class DeclAvailabilityChecker : public DeclVisitor { } // end anonymous namespace -static void checkExtensionGenericParamAccess(const ExtensionDecl *ED) { +static void checkExtensionAccess(const ExtensionDecl *ED) { auto *AA = ED->getAttrs().getAttribute(); if (!AA) return; @@ -2523,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, @@ -2660,13 +2796,10 @@ void swift::checkAccessControl(Decl *D) { AccessControlChecker(allowInlineable).visit(D); UsableFromInlineChecker().visit(D); } else if (auto *ED = dyn_cast(D)) { - checkExtensionGenericParamAccess(ED); + checkExtensionAccess(ED); registerPackageAccessForPackageExtendedType(ED); } - if (isa(D)) - return; - auto where = ExportContext::forDeclSignature(D); if (where.isImplicit()) return; diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 9232601deb7b5..f4a8dae839360 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -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(dc)) diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index a290483e08c72..f213579f07a17 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -3719,11 +3719,11 @@ class DeclChecker : public DeclVisitor { TypeChecker::checkProtocolSelfRequirements(FD); } - checkAccessControl(FD); - TypeChecker::checkParameterList(FD->getParameters(), FD); } + checkAccessControl(FD); + TypeChecker::checkDeclAttributes(FD); TypeChecker::checkDistributedFunc(FD); diff --git a/test/ClangImporter/Inputs/availability_domains_bridging_header.h b/test/ClangImporter/Inputs/availability_domains_bridging_header.h index 18fdfc79293a5..66f8dcf5cb153 100644 --- a/test/ClangImporter/Inputs/availability_domains_bridging_header.h +++ b/test/ClangImporter/Inputs/availability_domains_bridging_header.h @@ -1,11 +1,7 @@ -#include - -static struct __AvailabilityDomain bay_bridge - __attribute__((availability_domain(BayBridge))) = { - __AVAILABILITY_DOMAIN_ENABLED, 0}; -static struct __AvailabilityDomain golden_gate_bridge - __attribute__((availability_domain(GoldenGateBridge))) = { - __AVAILABILITY_DOMAIN_DISABLED, 0}; +#include + +CLANG_DISABLED_AVAILABILITY_DOMAIN(BayBridge); +CLANG_DISABLED_AVAILABILITY_DOMAIN(GoldenGateBridge); #define AVAIL 0 #define UNAVAIL 1 diff --git a/test/ClangImporter/access-level-import-availability-custom-domains.swift b/test/ClangImporter/access-level-import-availability-custom-domains.swift new file mode 100644 index 0000000000000..6963ed1f1532b --- /dev/null +++ b/test/ClangImporter/access-level-import-availability-custom-domains.swift @@ -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 { + 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() { } +} diff --git a/test/IRGen/Inputs/AvailabilityDomains.h b/test/IRGen/Inputs/AvailabilityDomains.h index 3248ee721e363..ad923bc48a39b 100644 --- a/test/IRGen/Inputs/AvailabilityDomains.h +++ b/test/IRGen/Inputs/AvailabilityDomains.h @@ -1,16 +1,10 @@ -#include - -static struct __AvailabilityDomain __EnabledDomain __attribute__(( - availability_domain(EnabledDomain))) = {__AVAILABILITY_DOMAIN_ENABLED, 0}; - -static struct __AvailabilityDomain __DisabledDomain __attribute__(( - availability_domain(DisabledDomain))) = {__AVAILABILITY_DOMAIN_DISABLED, 0}; +#include int dynamic_domain_pred(); -static struct __AvailabilityDomain __DynamicDomain - __attribute__((availability_domain(DynamicDomain))) = { - __AVAILABILITY_DOMAIN_DYNAMIC, dynamic_domain_pred}; +CLANG_ENABLED_AVAILABILITY_DOMAIN(EnabledDomain); +CLANG_DISABLED_AVAILABILITY_DOMAIN(DisabledDomain); +CLANG_DYNAMIC_AVAILABILITY_DOMAIN(DynamicDomain, dynamic_domain_pred); #define AVAIL 0 #define UNAVAIL 1 diff --git a/test/Inputs/custom-modules/availability-domains/Lakes.h b/test/Inputs/custom-modules/availability-domains/Lakes.h new file mode 100644 index 0000000000000..588bd346e965e --- /dev/null +++ b/test/Inputs/custom-modules/availability-domains/Lakes.h @@ -0,0 +1,12 @@ +#include + +CLANG_ENABLED_AVAILABILITY_DOMAIN(Salt); + +#define AVAIL 0 +#define UNAVAIL 1 + +__attribute__((availability(domain:Salt, AVAIL))) +void available_in_salt(void); + +#undef UNAVAIL +#undef AVAIL diff --git a/test/Inputs/custom-modules/availability-domains/Oceans.h b/test/Inputs/custom-modules/availability-domains/Oceans.h index d95f5b7d4a18c..57a50b7915a9f 100644 --- a/test/Inputs/custom-modules/availability-domains/Oceans.h +++ b/test/Inputs/custom-modules/availability-domains/Oceans.h @@ -1,15 +1,11 @@ #include -#include +#include int arctic_pred(void); int pacific_pred(void); -static struct __AvailabilityDomain arctic_domain - __attribute__((availability_domain(Arctic))) = { - __AVAILABILITY_DOMAIN_DYNAMIC, arctic_pred}; -static struct __AvailabilityDomain pacific_domain - __attribute__((availability_domain(Pacific))) = { - __AVAILABILITY_DOMAIN_DYNAMIC, pacific_pred}; +CLANG_DYNAMIC_AVAILABILITY_DOMAIN(Arctic, arctic_pred); +CLANG_DYNAMIC_AVAILABILITY_DOMAIN(Pacific, pacific_pred); #define AVAIL 0 #define UNAVAIL 1 diff --git a/test/Inputs/custom-modules/availability-domains/Rivers.h b/test/Inputs/custom-modules/availability-domains/Rivers.h index 9b026707be742..e36c41d83e001 100644 --- a/test/Inputs/custom-modules/availability-domains/Rivers.h +++ b/test/Inputs/custom-modules/availability-domains/Rivers.h @@ -1,7 +1,9 @@ -#include +#include -static struct __AvailabilityDomain colorado_domain __attribute__(( - availability_domain(Colorado))) = {__AVAILABILITY_DOMAIN_DISABLED, 0}; +CLANG_DISABLED_AVAILABILITY_DOMAIN(Colorado); + +__attribute__((deprecated("Use Colorado instead"))) +CLANG_DISABLED_AVAILABILITY_DOMAIN(Grand); #define AVAIL 0 #define UNAVAIL 1 diff --git a/test/Inputs/custom-modules/availability-domains/Seas.h b/test/Inputs/custom-modules/availability-domains/Seas.h index a5795bb07356c..87541fc7794a0 100644 --- a/test/Inputs/custom-modules/availability-domains/Seas.h +++ b/test/Inputs/custom-modules/availability-domains/Seas.h @@ -1,9 +1,7 @@ -#include +#include -static struct __AvailabilityDomain baltic_domain __attribute__(( - availability_domain(Baltic))) = {__AVAILABILITY_DOMAIN_ENABLED, 0}; -static struct __AvailabilityDomain _mediterranean __attribute__(( - availability_domain(Mediterranean))) = {__AVAILABILITY_DOMAIN_ENABLED, 0}; +CLANG_ENABLED_AVAILABILITY_DOMAIN(Baltic); +CLANG_DISABLED_AVAILABILITY_DOMAIN(Mediterranean); #define AVAIL 0 #define UNAVAIL 1 diff --git a/test/Inputs/custom-modules/availability-domains/module.modulemap b/test/Inputs/custom-modules/availability-domains/module.modulemap index 62930e7c437ab..3d9316f279f71 100644 --- a/test/Inputs/custom-modules/availability-domains/module.modulemap +++ b/test/Inputs/custom-modules/availability-domains/module.modulemap @@ -12,3 +12,8 @@ module Seas { header "Seas.h" export * } + +module Lakes { + header "Lakes.h" + export * +} diff --git a/test/SILGen/Inputs/AvailabilityDomains.h b/test/SILGen/Inputs/AvailabilityDomains.h index 213dae3773426..9806517df089d 100644 --- a/test/SILGen/Inputs/AvailabilityDomains.h +++ b/test/SILGen/Inputs/AvailabilityDomains.h @@ -1,18 +1,10 @@ -#include - -static struct __AvailabilityDomain __EnabledDomain - __attribute__((availability_domain(EnabledDomain))) = { - __AVAILABILITY_DOMAIN_ENABLED, 0}; - -static struct __AvailabilityDomain __DisabledDomain - __attribute__((availability_domain(DisabledDomain))) = { - __AVAILABILITY_DOMAIN_DISABLED, 0}; +#include int dynamic_domain_pred(); -static struct __AvailabilityDomain __DynamicDomain - __attribute__((availability_domain(DynamicDomain))) = { - __AVAILABILITY_DOMAIN_DYNAMIC, dynamic_domain_pred}; +CLANG_ENABLED_AVAILABILITY_DOMAIN(EnabledDomain); +CLANG_DISABLED_AVAILABILITY_DOMAIN(DisabledDomain); +CLANG_DYNAMIC_AVAILABILITY_DOMAIN(DynamicDomain, dynamic_domain_pred); #define AVAIL 0 #define UNAVAIL 1