@@ -541,87 +541,93 @@ 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
+ static bool constraintIndicatesRuntimeUnavailability (
563
+ const AvailabilityConstraint &constraint, const ASTContext &ctx) {
564
+ switch (constraint.getReason ()) {
565
+ case AvailabilityConstraint::Reason::UnconditionallyUnavailable: {
566
+ return true ;
567
+ }
568
+ case AvailabilityConstraint::Reason::UnavailableForDeployment:
569
+ case AvailabilityConstraint::Reason::Obsoleted:
570
+ case AvailabilityConstraint::Reason::PotentiallyUnavailable:
571
+ return false ;
572
+ }
573
+ }
574
+
575
+ // / Computes the `SemanticDeclAvailability` value for `decl`.
576
+ static SemanticDeclAvailability getSemanticDeclAvailability (const Decl *decl) {
567
577
// Don't trust unavailability on declarations from Clang modules.
568
578
if (isa<ClangModuleUnit>(decl->getDeclContext ()->getModuleScopeContext ()))
569
- return false ;
579
+ return SemanticDeclAvailability::PotentiallyAvailable;
580
+
581
+ // Check whether the decl is unavailable at all.
582
+ if (!decl->isUnavailable ())
583
+ return SemanticDeclAvailability::PotentiallyAvailable;
570
584
571
585
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 ();
586
+ auto compatibilityDomains = availabilityDomainsForABICompatibility (ctx);
587
+ auto potentiallyAvailableDomains = compatibilityDomains;
588
+
589
+ AvailabilityConstraintFlags flags;
590
+
591
+ // Semantic availability was already computed separately for any enclosing
592
+ // extension.
593
+ flags |= AvailabilityConstraintFlag::SkipEnclosingExtension;
594
+
595
+ // FIXME: [availability] Inactive domains have to be included because iOS
596
+ // availability is considered inactive when compiling a zippered module.
597
+ flags |= AvailabilityConstraintFlag::IncludeAllDomains;
598
+
599
+ auto constraints = getAvailabilityConstraintsForDecl (
600
+ decl, AvailabilityContext::forInliningTarget (ctx), flags);
601
+
602
+ for (auto constraint : constraints) {
603
+ if (!constraintIndicatesRuntimeUnavailability (constraint, ctx))
604
+ continue ;
605
+
606
+ // Check whether the constraint is from a relevant domain.
607
+ auto domain = constraint.getDomain ();
584
608
bool isCompabilityDomainDescendant =
585
609
llvm::find_if (compatibilityDomains,
586
610
[&domain](AvailabilityDomain compatibilityDomain) {
587
611
return compatibilityDomain.contains (domain);
588
612
}) != compatibilityDomains.end ();
589
613
614
+ if (!domain.isActive (ctx) && !isCompabilityDomainDescendant)
615
+ continue ;
616
+
590
617
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);
598
- }
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 ;
618
+ // If the decl is still potentially available in some compatibility
619
+ // domain, keep looking at the remaining constraints.
620
+ potentiallyAvailableDomains.remove (domain);
621
+ if (!potentiallyAvailableDomains.empty ())
622
+ continue ;
604
623
}
605
- }
606
-
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 ;
612
624
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 ;
625
+ // Either every compatibility domain has been proven unavailable or this
626
+ // constraint proves runtime unavailability on its own.
627
+ return SemanticDeclAvailability::AlwaysUnavailableABICompatible;
618
628
}
619
-
620
- // Verify that there aren't any explicitly available descendant domains.
621
- if (availableDescendantDomains.size () > 0 )
622
- return false ;
623
629
624
- return true ;
630
+ return SemanticDeclAvailability::PotentiallyAvailable ;
625
631
}
626
632
627
633
SemanticDeclAvailability
@@ -634,22 +640,21 @@ SemanticDeclAvailabilityRequest::evaluate(Evaluator &evaluator,
634
640
evaluator, SemanticDeclAvailabilityRequest{parent}, inherited);
635
641
}
636
642
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;
643
+ // If the inherited semantic availability is already maximally unavailable
644
+ // then skip computing unavailability for this declaration.
645
+ if (inherited == SemanticDeclAvailability::AlwaysUnavailableABICompatible)
646
+ return SemanticDeclAvailability::AlwaysUnavailableABICompatible;
644
647
645
- return SemanticDeclAvailability::PotentiallyAvailable;
648
+ auto availability = getSemanticDeclAvailability (decl);
649
+ return std::max (inherited, availability);
646
650
}
647
651
648
652
bool Decl::isUnreachableAtRuntime () const {
649
653
auto availability = evaluateOrDefault (
650
654
getASTContext ().evaluator , SemanticDeclAvailabilityRequest{this },
651
655
SemanticDeclAvailability::PotentiallyAvailable);
652
- return availability == SemanticDeclAvailability::CompletelyUnavailable;
656
+ return availability ==
657
+ SemanticDeclAvailability::AlwaysUnavailableABICompatible;
653
658
}
654
659
655
660
static UnavailableDeclOptimization
@@ -852,8 +857,6 @@ std::optional<llvm::VersionTuple> SemanticAvailableAttr::getIntroduced() const {
852
857
853
858
std::optional<AvailabilityRange>
854
859
SemanticAvailableAttr::getIntroducedRange (const ASTContext &Ctx) const {
855
- DEBUG_ASSERT (getDomain ().isActive (Ctx));
856
-
857
860
auto *attr = getParsedAttr ();
858
861
if (!attr->getRawIntroduced ().has_value ()) {
859
862
// For versioned domains, an "introduced:" version is always required to
@@ -892,8 +895,6 @@ std::optional<llvm::VersionTuple> SemanticAvailableAttr::getDeprecated() const {
892
895
893
896
std::optional<AvailabilityRange>
894
897
SemanticAvailableAttr::getDeprecatedRange (const ASTContext &Ctx) const {
895
- DEBUG_ASSERT (getDomain ().isActive (Ctx));
896
-
897
898
auto *attr = getParsedAttr ();
898
899
if (!attr->getRawDeprecated ().has_value ()) {
899
900
// Regardless of the whether the domain supports versions or not, an
@@ -923,8 +924,6 @@ std::optional<llvm::VersionTuple> SemanticAvailableAttr::getObsoleted() const {
923
924
924
925
std::optional<AvailabilityRange>
925
926
SemanticAvailableAttr::getObsoletedRange (const ASTContext &Ctx) const {
926
- DEBUG_ASSERT (getDomain ().isActive (Ctx));
927
-
928
927
auto *attr = getParsedAttr ();
929
928
930
929
// Obsoletion always requires a version.
0 commit comments