16
16
17
17
#include " swift/AST/ASTContext.h"
18
18
#include " swift/AST/Attr.h"
19
+ #include " swift/AST/AvailabilityConstraint.h"
20
+ #include " swift/AST/AvailabilityContext.h"
19
21
#include " swift/AST/AvailabilityDomain.h"
20
22
#include " swift/AST/AvailabilityInference.h"
21
23
#include " swift/AST/AvailabilityRange.h"
@@ -629,27 +631,84 @@ Decl::getUnavailableAttr(bool ignoreAppExtensions) const {
629
631
return std::nullopt;
630
632
}
631
633
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.
634
655
if (isa<ClangModuleUnit>(decl->getDeclContext ()->getModuleScopeContext ()))
635
656
return false ;
636
657
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
+ }
640
693
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 ())
646
698
return false ;
647
699
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 ;
651
710
652
- // FIXME: Support zippered frameworks (rdar://125371621)
711
+ // FIXME: [availability] Support zippered frameworks (rdar://125371621)
653
712
// If we have a target variant (e.g. we're building a zippered macOS
654
713
// framework) then the decl is only unreachable if it is unavailable for both
655
714
// the primary target and the target variant.
@@ -670,7 +729,7 @@ SemanticDeclAvailabilityRequest::evaluate(Evaluator &evaluator,
670
729
}
671
730
672
731
if (inherited == SemanticDeclAvailability::CompletelyUnavailable ||
673
- isDeclCompletelyUnavailable (decl))
732
+ isUnavailableForAllABICompatiblePlatforms (decl))
674
733
return SemanticDeclAvailability::CompletelyUnavailable;
675
734
676
735
if (inherited == SemanticDeclAvailability::ConditionallyUnavailable ||
@@ -699,14 +758,6 @@ getEffectiveUnavailableDeclOptimization(ASTContext &ctx) {
699
758
if (ctx.LangOpts .UnavailableDeclOptimizationMode .has_value ())
700
759
return *ctx.LangOpts .UnavailableDeclOptimizationMode ;
701
760
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
-
710
761
return UnavailableDeclOptimization::None;
711
762
}
712
763
0 commit comments