@@ -541,87 +541,89 @@ std::optional<SemanticAvailableAttr> Decl::getUnavailableAttr() const {
541
541
return std::nullopt;
542
542
}
543
543
544
- static llvm::SmallVector <AvailabilityDomain, 2 >
544
+ static llvm::SmallSetVector <AvailabilityDomain, 2 >
545
545
availabilityDomainsForABICompatibility (const ASTContext &ctx) {
546
- llvm::SmallVector <AvailabilityDomain, 2 > domains;
546
+ llvm::SmallSetVector <AvailabilityDomain, 2 > domains;
547
547
548
548
// Regardless of target platform, binaries built for Embedded do not require
549
549
// compatibility.
550
550
if (ctx.LangOpts .hasFeature (Feature::Embedded))
551
551
return domains;
552
552
553
553
if (auto targetDomain = AvailabilityDomain::forTargetPlatform (ctx))
554
- domains.push_back (targetDomain->getABICompatibilityDomain ());
555
-
554
+ domains.insert (targetDomain->getABICompatibilityDomain ());
555
+
556
556
if (auto variantDomain = AvailabilityDomain::forTargetVariantPlatform (ctx))
557
- domains.push_back (variantDomain->getABICompatibilityDomain ());
557
+ domains.insert (variantDomain->getABICompatibilityDomain ());
558
558
559
559
return domains;
560
560
}
561
561
562
- // / Returns true if \p decl is proven to be unavailable for all platforms that
563
- // / external modules interacting with this module could target. A declaration
564
- // / that is not proven to be unavailable in this way could be reachable at
565
- // / runtime, even if it is unavailable to all code in this module.
566
- static bool isUnavailableForAllABICompatiblePlatforms (const Decl *decl) {
562
+ // / Computes the `SemanticDeclAvailability` value for `decl`.
563
+ static SemanticDeclAvailability getSemanticDeclAvailability (const Decl *decl) {
567
564
// Don't trust unavailability on declarations from Clang modules.
568
565
if (isa<ClangModuleUnit>(decl->getDeclContext ()->getModuleScopeContext ()))
569
- return false ;
566
+ return SemanticDeclAvailability::PotentiallyAvailable;
567
+
568
+ // Check whether the decl is unavailable at all.
569
+ if (!decl->isUnavailable ())
570
+ return SemanticDeclAvailability::PotentiallyAvailable;
570
571
571
572
auto &ctx = decl->getASTContext ();
572
- llvm::SmallVector<AvailabilityDomain, 2 > compatibilityDomains =
573
- availabilityDomainsForABICompatibility (ctx);
574
-
575
- llvm::SmallSet<AvailabilityDomain, 8 > unavailableDescendantDomains;
576
- llvm::SmallSet<AvailabilityDomain, 8 > availableDescendantDomains;
577
-
578
- // Build up the collection of relevant available and unavailable platform
579
- // domains by looking at all the @available attributes. Along the way, we
580
- // may find an attribute that makes the declaration universally unavailable
581
- // in which case platform availability is irrelevant.
582
- for (auto attr : decl->getSemanticAvailableAttrs (/* includeInactive=*/ true )) {
583
- auto domain = attr.getDomain ();
584
- bool isCompabilityDomainDescendant =
585
- llvm::find_if (compatibilityDomains,
586
- [&domain](AvailabilityDomain compatibilityDomain) {
587
- return compatibilityDomain.contains (domain);
588
- }) != compatibilityDomains.end ();
589
-
590
- if (isCompabilityDomainDescendant) {
591
- // Record the whether the descendant domain is marked available
592
- // or unavailable. Unavailability overrides availability.
593
- if (attr.isUnconditionallyUnavailable ()) {
594
- availableDescendantDomains.erase (domain);
595
- unavailableDescendantDomains.insert (domain);
596
- } else if (!unavailableDescendantDomains.contains (domain)) {
597
- availableDescendantDomains.insert (domain);
573
+ auto compatibilityDomains = availabilityDomainsForABICompatibility (ctx);
574
+ auto remainingCompatibilityDomains = compatibilityDomains;
575
+
576
+ AvailabilityConstraintFlags flags;
577
+
578
+ // Semantic availability was already computed separately for any enclosing
579
+ // extension.
580
+ flags |= AvailabilityConstraintFlag::SkipEnclosingExtension;
581
+
582
+ // FIXME: [availability] Inactive domains have to be included because iOS
583
+ // availability is considered inactive when compiling a zippered module.
584
+ flags |= AvailabilityConstraintFlag::IncludeAllDomains;
585
+
586
+ auto constraints = getAvailabilityConstraintsForDecl (
587
+ decl, AvailabilityContext::forInliningTarget (ctx), flags);
588
+ unsigned otherUnavailableDomainCount = 0 ;
589
+
590
+ for (auto constraint : constraints) {
591
+ auto domain = constraint.getDomain ();
592
+
593
+ switch (constraint.getReason ()) {
594
+ case AvailabilityConstraint::Reason::UnconditionallyUnavailable: {
595
+ bool isCompabilityDomainDescendant =
596
+ llvm::find_if (compatibilityDomains,
597
+ [&domain](AvailabilityDomain compatibilityDomain) {
598
+ return compatibilityDomain.contains (domain);
599
+ }) != compatibilityDomains.end ();
600
+
601
+ if (isCompabilityDomainDescendant) {
602
+ remainingCompatibilityDomains.remove (domain);
603
+ break ;
598
604
}
599
- } else if (attr.isActive (ctx)) {
600
- // The declaration is always unavailable if an active attribute from a
601
- // domain outside the compatibility hierarchy indicates unavailability.
602
- if (attr.isUnconditionallyUnavailable ())
603
- return true ;
605
+
606
+ if (domain.isActive (ctx))
607
+ otherUnavailableDomainCount++;
608
+ break ;
609
+ }
610
+ case AvailabilityConstraint::Reason::UnavailableForDeployment:
611
+ case AvailabilityConstraint::Reason::Obsoleted:
612
+ case AvailabilityConstraint::Reason::PotentiallyUnavailable:
613
+ break ;
604
614
}
605
615
}
606
616
607
- // If there aren't any compatibility domains to check and we didn't find any
608
- // other active attributes that make the declaration unavailable, then it must
609
- // be available.
610
- if (compatibilityDomains.empty ())
611
- return false ;
617
+ if (otherUnavailableDomainCount > 0 )
618
+ return SemanticDeclAvailability::AlwaysUnavailableABICompatible;
612
619
613
- // Verify that the declaration has been marked unavailable in every
614
- // compatibility domain.
615
- for (auto compatibilityDomain : compatibilityDomains) {
616
- if (!unavailableDescendantDomains.contains (compatibilityDomain))
617
- return false ;
618
- }
619
-
620
- // Verify that there aren't any explicitly available descendant domains.
621
- if (availableDescendantDomains.size () > 0 )
622
- return false ;
620
+ // Check whether the declaration has been marked unavailable in all
621
+ // compatibility domains. If it hasn't, then the declaration may be usable
622
+ // by some client compiled with different settings.
623
+ if (remainingCompatibilityDomains.size () > 0 )
624
+ return SemanticDeclAvailability::PotentiallyAvailable;
623
625
624
- return true ;
626
+ return SemanticDeclAvailability::AlwaysUnavailableABICompatible ;
625
627
}
626
628
627
629
SemanticDeclAvailability
@@ -634,22 +636,21 @@ SemanticDeclAvailabilityRequest::evaluate(Evaluator &evaluator,
634
636
evaluator, SemanticDeclAvailabilityRequest{parent}, inherited);
635
637
}
636
638
637
- if (inherited == SemanticDeclAvailability::CompletelyUnavailable ||
638
- isUnavailableForAllABICompatiblePlatforms (decl))
639
- return SemanticDeclAvailability::CompletelyUnavailable;
640
-
641
- if (inherited == SemanticDeclAvailability::ConditionallyUnavailable ||
642
- decl->isUnavailable ())
643
- return SemanticDeclAvailability::ConditionallyUnavailable;
639
+ // If the inherited semantic availability is already maximally unavailable
640
+ // then skip computing unavailability for this declaration.
641
+ if (inherited == SemanticDeclAvailability::AlwaysUnavailableABICompatible)
642
+ return SemanticDeclAvailability::AlwaysUnavailableABICompatible;
644
643
645
- return SemanticDeclAvailability::PotentiallyAvailable;
644
+ auto availability = getSemanticDeclAvailability (decl);
645
+ return std::max (inherited, availability);
646
646
}
647
647
648
648
bool Decl::isUnreachableAtRuntime () const {
649
649
auto availability = evaluateOrDefault (
650
650
getASTContext ().evaluator , SemanticDeclAvailabilityRequest{this },
651
651
SemanticDeclAvailability::PotentiallyAvailable);
652
- return availability == SemanticDeclAvailability::CompletelyUnavailable;
652
+ return availability ==
653
+ SemanticDeclAvailability::AlwaysUnavailableABICompatible;
653
654
}
654
655
655
656
static UnavailableDeclOptimization
@@ -852,8 +853,6 @@ std::optional<llvm::VersionTuple> SemanticAvailableAttr::getIntroduced() const {
852
853
853
854
std::optional<AvailabilityRange>
854
855
SemanticAvailableAttr::getIntroducedRange (const ASTContext &Ctx) const {
855
- DEBUG_ASSERT (getDomain ().isActive (Ctx));
856
-
857
856
auto *attr = getParsedAttr ();
858
857
if (!attr->getRawIntroduced ().has_value ()) {
859
858
// For versioned domains, an "introduced:" version is always required to
@@ -892,8 +891,6 @@ std::optional<llvm::VersionTuple> SemanticAvailableAttr::getDeprecated() const {
892
891
893
892
std::optional<AvailabilityRange>
894
893
SemanticAvailableAttr::getDeprecatedRange (const ASTContext &Ctx) const {
895
- DEBUG_ASSERT (getDomain ().isActive (Ctx));
896
-
897
894
auto *attr = getParsedAttr ();
898
895
if (!attr->getRawDeprecated ().has_value ()) {
899
896
// Regardless of the whether the domain supports versions or not, an
@@ -923,8 +920,6 @@ std::optional<llvm::VersionTuple> SemanticAvailableAttr::getObsoleted() const {
923
920
924
921
std::optional<AvailabilityRange>
925
922
SemanticAvailableAttr::getObsoletedRange (const ASTContext &Ctx) const {
926
- DEBUG_ASSERT (getDomain ().isActive (Ctx));
927
-
928
923
auto *attr = getParsedAttr ();
929
924
930
925
// Obsoletion always requires a version.
0 commit comments