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"
@@ -454,17 +456,13 @@ Decl::getSemanticAvailableAttr(const AvailableAttr *attr) const {
454
456
}
455
457
456
458
std::optional<SemanticAvailableAttr>
457
- Decl::getActiveAvailableAttrForCurrentPlatform (bool ignoreAppExtensions ) const {
459
+ Decl::getActiveAvailableAttrForCurrentPlatform () const {
458
460
std::optional<SemanticAvailableAttr> bestAttr;
459
461
460
462
for (auto attr : getSemanticAvailableAttrs (/* includingInactive=*/ false )) {
461
463
if (!attr.isPlatformSpecific ())
462
464
continue ;
463
465
464
- if (ignoreAppExtensions &&
465
- isApplicationExtensionPlatform (attr.getPlatform ()))
466
- continue ;
467
-
468
466
// We have an attribute that is active for the platform, but is it more
469
467
// specific than our current best?
470
468
if (!bestAttr || inheritsAvailabilityFromPlatform (
@@ -575,23 +573,17 @@ bool Decl::isUnavailableInCurrentSwiftVersion() const {
575
573
return false ;
576
574
}
577
575
578
- std::optional<SemanticAvailableAttr>
579
- getDeclUnavailableAttr (const Decl *D, bool ignoreAppExtensions) {
576
+ std::optional<SemanticAvailableAttr> getDeclUnavailableAttr (const Decl *D) {
580
577
auto &ctx = D->getASTContext ();
581
578
std::optional<SemanticAvailableAttr> result;
582
- auto bestActive =
583
- D->getActiveAvailableAttrForCurrentPlatform (ignoreAppExtensions);
579
+ auto bestActive = D->getActiveAvailableAttrForCurrentPlatform ();
584
580
585
581
for (auto attr : D->getSemanticAvailableAttrs (/* includingInactive=*/ false )) {
586
582
// If this is a platform-specific attribute and it isn't the most
587
583
// specific attribute for the current platform, we're done.
588
584
if (attr.isPlatformSpecific () && (!bestActive || attr != bestActive))
589
585
continue ;
590
586
591
- if (ignoreAppExtensions &&
592
- isApplicationExtensionPlatform (attr.getPlatform ()))
593
- continue ;
594
-
595
587
// Unconditional unavailable.
596
588
if (attr.isUnconditionallyUnavailable ())
597
589
return attr;
@@ -610,9 +602,8 @@ getDeclUnavailableAttr(const Decl *D, bool ignoreAppExtensions) {
610
602
return result;
611
603
}
612
604
613
- std::optional<SemanticAvailableAttr>
614
- Decl::getUnavailableAttr (bool ignoreAppExtensions) const {
615
- if (auto attr = getDeclUnavailableAttr (this , ignoreAppExtensions))
605
+ std::optional<SemanticAvailableAttr> Decl::getUnavailableAttr () const {
606
+ if (auto attr = getDeclUnavailableAttr (this ))
616
607
return attr;
617
608
618
609
// If D is an extension member, check if the extension is unavailable.
@@ -624,36 +615,89 @@ Decl::getUnavailableAttr(bool ignoreAppExtensions) const {
624
615
// and the availability of other categories. rdar://problem/53956555
625
616
if (!getClangNode ())
626
617
if (auto ext = dyn_cast<ExtensionDecl>(getDeclContext ()))
627
- return ext->getUnavailableAttr (ignoreAppExtensions );
618
+ return ext->getUnavailableAttr ();
628
619
629
620
return std::nullopt;
630
621
}
631
622
632
- static bool isDeclCompletelyUnavailable (const Decl *decl) {
633
- // Don't trust unavailability on declarations from clang modules.
623
+ static llvm::SmallVector<AvailabilityDomain, 2 >
624
+ availabilityDomainsForABICompatibility (const ASTContext &ctx) {
625
+ llvm::SmallVector<AvailabilityDomain, 2 > domains;
626
+
627
+ // Regardless of target platform, binaries built for Embedded do not require
628
+ // compatibility.
629
+ if (ctx.LangOpts .hasFeature (Feature::Embedded))
630
+ return domains;
631
+
632
+ if (auto targetDomain = AvailabilityDomain::forTargetPlatform (ctx))
633
+ domains.push_back (targetDomain->getABICompatibilityDomain ());
634
+
635
+ if (auto variantDomain = AvailabilityDomain::forTargetVariantPlatform (ctx))
636
+ domains.push_back (variantDomain->getABICompatibilityDomain ());
637
+
638
+ return domains;
639
+ }
640
+
641
+ // / Returns true if \p decl is proven to be unavailable for all platforms that
642
+ // / external modules interacting with this module could target. A declaration
643
+ // / that is not proven to be unavailable in this way could be reachable at
644
+ // / runtime, even if it is unavailable to all code in this module.
645
+ static bool isUnavailableForAllABICompatiblePlatforms (const Decl *decl) {
646
+ // Don't trust unavailability on declarations from Clang modules.
634
647
if (isa<ClangModuleUnit>(decl->getDeclContext ()->getModuleScopeContext ()))
635
648
return false ;
636
649
637
- auto unavailableAttr = decl->getUnavailableAttr (/* ignoreAppExtensions=*/ true );
638
- if (!unavailableAttr)
639
- return false ;
650
+ auto &ctx = decl->getASTContext ();
651
+ llvm::SmallVector<AvailabilityDomain, 2 > compatibilityDomains =
652
+ availabilityDomainsForABICompatibility (ctx);
653
+
654
+ llvm::SmallSet<AvailabilityDomain, 8 > unavailableDescendantDomains;
655
+ llvm::SmallSet<AvailabilityDomain, 8 > availableDescendantDomains;
656
+
657
+ // Build up the collection of relevant available and unavailable platform
658
+ // domains by looking at all the @available attributes. Along the way, we
659
+ // may find an attribute that makes the declaration universally unavailable
660
+ // in which case platform availability is irrelevant.
661
+ for (auto attr : decl->getSemanticAvailableAttrs (/* includeInactive=*/ true )) {
662
+ auto domain = attr.getDomain ();
663
+ bool isCompabilityDomainDescendant =
664
+ llvm::find_if (compatibilityDomains,
665
+ [&domain](AvailabilityDomain compatibilityDomain) {
666
+ return compatibilityDomain.contains (domain);
667
+ }) != compatibilityDomains.end ();
668
+
669
+ if (isCompabilityDomainDescendant) {
670
+ // Record the whether the descendant domain is marked available
671
+ // or unavailable. Unavailability overrides availability.
672
+ if (attr.isUnconditionallyUnavailable ()) {
673
+ availableDescendantDomains.erase (domain);
674
+ unavailableDescendantDomains.insert (domain);
675
+ } else if (!unavailableDescendantDomains.contains (domain)) {
676
+ availableDescendantDomains.insert (domain);
677
+ }
678
+ } else if (attr.isActive (ctx)) {
679
+ // The declaration is always unavailable if an active attribute from a
680
+ // domain outside the compatibility hierarchy indicates unavailability.
681
+ if (attr.isUnconditionallyUnavailable ())
682
+ return true ;
683
+ }
684
+ }
640
685
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 ())
686
+ // If there aren't any compatibility domains to check and we didn't find any
687
+ // other active attributes that make the declaration unavailable, then it must
688
+ // be available.
689
+ if (compatibilityDomains.empty ())
646
690
return false ;
647
691
648
- // Universally unavailable declarations are always completely unavailable.
649
- if (unavailableAttr-> getPlatform () == PlatformKind::none)
650
- return true ;
651
-
652
- // FIXME: Support zippered frameworks (rdar://125371621)
653
- // If we have a target variant (e.g. we're building a zippered macOS
654
- // framework) then the decl is only unreachable if it is unavailable for both
655
- // the primary target and the target variant .
656
- if (decl-> getASTContext (). LangOpts . TargetVariant . has_value () )
692
+ // Verify that the declaration has been marked unavailable in every
693
+ // compatibility domain.
694
+ for ( auto compatibilityDomain : compatibilityDomains) {
695
+ if (!unavailableDescendantDomains. contains (compatibilityDomain))
696
+ return false ;
697
+ }
698
+
699
+ // Verify that there aren't any explicitly available descendant domains .
700
+ if (availableDescendantDomains. size () > 0 )
657
701
return false ;
658
702
659
703
return true ;
@@ -670,7 +714,7 @@ SemanticDeclAvailabilityRequest::evaluate(Evaluator &evaluator,
670
714
}
671
715
672
716
if (inherited == SemanticDeclAvailability::CompletelyUnavailable ||
673
- isDeclCompletelyUnavailable (decl))
717
+ isUnavailableForAllABICompatiblePlatforms (decl))
674
718
return SemanticDeclAvailability::CompletelyUnavailable;
675
719
676
720
if (inherited == SemanticDeclAvailability::ConditionallyUnavailable ||
@@ -699,14 +743,6 @@ getEffectiveUnavailableDeclOptimization(ASTContext &ctx) {
699
743
if (ctx.LangOpts .UnavailableDeclOptimizationMode .has_value ())
700
744
return *ctx.LangOpts .UnavailableDeclOptimizationMode ;
701
745
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
746
return UnavailableDeclOptimization::None;
711
747
}
712
748
0 commit comments