1616
1717#include " swift/AST/ASTContext.h"
1818#include " swift/AST/Attr.h"
19+ #include " swift/AST/AvailabilityConstraint.h"
20+ #include " swift/AST/AvailabilityContext.h"
1921#include " swift/AST/AvailabilityDomain.h"
2022#include " swift/AST/AvailabilityInference.h"
2123#include " swift/AST/AvailabilityRange.h"
@@ -629,27 +631,84 @@ Decl::getUnavailableAttr(bool ignoreAppExtensions) const {
629631 return std::nullopt ;
630632}
631633
632- static bool isDeclCompletelyUnavailable (const Decl *decl) {
633- // Don't trust unavailability on declarations from clang modules.
634+ static llvm::SmallVector<AvailabilityDomain, 2 >
635+ availabilityDomainsForABICompatibility (const ASTContext &ctx) {
636+ llvm::SmallVector<AvailabilityDomain, 2 > domains;
637+
638+ // Regardless of target platform, binaries built for Embedded do not require
639+ // compatibility.
640+ if (ctx.LangOpts .hasFeature (Feature::Embedded))
641+ return domains;
642+
643+ if (auto targetDomain = AvailabilityDomain::forTargetPlatform (ctx))
644+ domains.push_back (targetDomain->getABICompatibilityDomain ());
645+
646+ return domains;
647+ }
648+
649+ // / Returns true if \p decl is proven to be unavailable for all platforms that
650+ // / external modules interacting with this module could target. A declaration
651+ // / that is not proven to be unavailable in this way could be reachable at
652+ // / runtime, even if it is unavailable to all code in this module.
653+ static bool isUnavailableForAllABICompatiblePlatforms (const Decl *decl) {
654+ // Don't trust unavailability on declarations from Clang modules.
634655 if (isa<ClangModuleUnit>(decl->getDeclContext ()->getModuleScopeContext ()))
635656 return false ;
636657
637- auto unavailableAttr = decl->getUnavailableAttr (/* ignoreAppExtensions=*/ true );
638- if (!unavailableAttr)
639- return false ;
658+ auto &ctx = decl->getASTContext ();
659+ llvm::SmallVector<AvailabilityDomain, 2 > compatibilityDomains =
660+ availabilityDomainsForABICompatibility (ctx);
661+
662+ llvm::SmallSet<AvailabilityDomain, 8 > unavailableDescendantDomains;
663+ llvm::SmallSet<AvailabilityDomain, 8 > availableDescendantDomains;
664+
665+ // Build up the collection of relevant available and unavailable platform
666+ // domains by looking at all the @available attributes. Along the way, we
667+ // may find an attribute that makes the declaration universally unavailable
668+ // in which case platform availability is irrelevant.
669+ for (auto attr : decl->getSemanticAvailableAttrs (/* includeInactive=*/ true )) {
670+ auto domain = attr.getDomain ();
671+ bool isCompabilityDomainDescendant =
672+ llvm::find_if (compatibilityDomains,
673+ [&domain](AvailabilityDomain compatibilityDomain) {
674+ return compatibilityDomain.contains (domain);
675+ }) != compatibilityDomains.end ();
676+
677+ if (isCompabilityDomainDescendant) {
678+ // Record the whether the descendant domain is marked available
679+ // or unavailable. Unavailability overrides availability.
680+ if (attr.isUnconditionallyUnavailable ()) {
681+ availableDescendantDomains.erase (domain);
682+ unavailableDescendantDomains.insert (domain);
683+ } else if (!unavailableDescendantDomains.contains (domain)) {
684+ availableDescendantDomains.insert (domain);
685+ }
686+ } else if (attr.isActive (ctx)) {
687+ // The declaration is always unavailable if an active attribute from a
688+ // domain outside the compatibility hierarchy indicates unavailability.
689+ if (attr.isUnconditionallyUnavailable ())
690+ return true ;
691+ }
692+ }
640693
641- // getUnavailableAttr() can return an @available attribute that is
642- // obsoleted for certain deployment targets or language modes. These decls
643- // can still be reached by code in other modules that is compiled with
644- // a different deployment target or language mode.
645- if (!unavailableAttr->isUnconditionallyUnavailable ())
694+ // If there aren't any compatibility domains to check and we didn't find any
695+ // other active attributes that make the declaration unavailable, then it must
696+ // be available.
697+ if (compatibilityDomains.empty ())
646698 return false ;
647699
648- // Universally unavailable declarations are always completely unavailable.
649- if (unavailableAttr->getPlatform () == PlatformKind::none)
650- return true ;
700+ // Verify that the declaration has been marked unavailable in every
701+ // compatibility domain.
702+ for (auto compatibilityDomain : compatibilityDomains) {
703+ if (!unavailableDescendantDomains.contains (compatibilityDomain))
704+ return false ;
705+ }
706+
707+ // Verify that there aren't any explicitly available descendant domains.
708+ if (availableDescendantDomains.size () > 0 )
709+ return false ;
651710
652- // FIXME: Support zippered frameworks (rdar://125371621)
711+ // FIXME: [availability] Support zippered frameworks (rdar://125371621)
653712 // If we have a target variant (e.g. we're building a zippered macOS
654713 // framework) then the decl is only unreachable if it is unavailable for both
655714 // the primary target and the target variant.
@@ -670,7 +729,7 @@ SemanticDeclAvailabilityRequest::evaluate(Evaluator &evaluator,
670729 }
671730
672731 if (inherited == SemanticDeclAvailability::CompletelyUnavailable ||
673- isDeclCompletelyUnavailable (decl))
732+ isUnavailableForAllABICompatiblePlatforms (decl))
674733 return SemanticDeclAvailability::CompletelyUnavailable;
675734
676735 if (inherited == SemanticDeclAvailability::ConditionallyUnavailable ||
@@ -699,14 +758,6 @@ getEffectiveUnavailableDeclOptimization(ASTContext &ctx) {
699758 if (ctx.LangOpts .UnavailableDeclOptimizationMode .has_value ())
700759 return *ctx.LangOpts .UnavailableDeclOptimizationMode ;
701760
702- // FIXME: Allow unavailable decl optimization on visionOS.
703- // visionOS must be ABI compatible with iOS. Enabling unavailable declaration
704- // optimizations naively would break compatibility since declarations marked
705- // unavailable on visionOS would be optimized regardless of whether they are
706- // available on iOS. rdar://116742214
707- if (ctx.LangOpts .Target .isXROS ())
708- return UnavailableDeclOptimization::None;
709-
710761 return UnavailableDeclOptimization::None;
711762}
712763
0 commit comments