@@ -541,122 +541,120 @@ std::optional<SemanticAvailableAttr> Decl::getUnavailableAttr() const {
541541 return std::nullopt ;
542542}
543543
544- static llvm::SmallVector <AvailabilityDomain, 2 >
544+ static llvm::SmallSetVector <AvailabilityDomain, 2 >
545545availabilityDomainsForABICompatibility (const ASTContext &ctx) {
546- llvm::SmallVector <AvailabilityDomain, 2 > domains;
546+ llvm::SmallSetVector <AvailabilityDomain, 2 > domains;
547547
548548 // Regardless of target platform, binaries built for Embedded do not require
549549 // compatibility.
550550 if (ctx.LangOpts .hasFeature (Feature::Embedded))
551551 return domains;
552552
553553 if (auto targetDomain = AvailabilityDomain::forTargetPlatform (ctx))
554- domains.push_back (targetDomain->getABICompatibilityDomain ());
555-
554+ domains.insert (targetDomain->getABICompatibilityDomain ());
555+
556556 if (auto variantDomain = AvailabilityDomain::forTargetVariantPlatform (ctx))
557- domains.push_back (variantDomain->getABICompatibilityDomain ());
557+ domains.insert (variantDomain->getABICompatibilityDomain ());
558558
559559 return domains;
560560}
561561
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 `DeclRuntimeAvailability` value for `decl`.
576+ static DeclRuntimeAvailability getDeclRuntimeAvailability (const Decl *decl) {
567577 // Don't trust unavailability on declarations from Clang modules.
568578 if (isa<ClangModuleUnit>(decl->getDeclContext ()->getModuleScopeContext ()))
569- return false ;
579+ return DeclRuntimeAvailability::PotentiallyAvailable;
580+
581+ // Check whether the decl is unavailable at all.
582+ if (!decl->isUnavailable ())
583+ return DeclRuntimeAvailability::PotentiallyAvailable;
570584
571585 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 ();
584608 bool isCompabilityDomainDescendant =
585609 llvm::find_if (compatibilityDomains,
586610 [&domain](AvailabilityDomain compatibilityDomain) {
587611 return compatibilityDomain.contains (domain);
588612 }) != compatibilityDomains.end ();
589613
614+ if (!domain.isActive (ctx) && !isCompabilityDomainDescendant)
615+ continue ;
616+
590617 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 ;
604623 }
605- }
606624
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-
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 DeclRuntimeAvailability::AlwaysUnavailableABICompatible;
618628 }
619-
620- // Verify that there aren't any explicitly available descendant domains.
621- if (availableDescendantDomains.size () > 0 )
622- return false ;
623629
624- return true ;
630+ return DeclRuntimeAvailability::PotentiallyAvailable ;
625631}
626632
627- SemanticDeclAvailability
628- SemanticDeclAvailabilityRequest ::evaluate (Evaluator &evaluator,
629- const Decl *decl) const {
630- auto inherited = SemanticDeclAvailability ::PotentiallyAvailable;
633+ DeclRuntimeAvailability
634+ DeclRuntimeAvailabilityRequest ::evaluate (Evaluator &evaluator,
635+ const Decl *decl) const {
636+ auto inherited = DeclRuntimeAvailability ::PotentiallyAvailable;
631637 if (auto *parent =
632638 AvailabilityInference::parentDeclForInferredAvailability (decl)) {
633639 inherited = evaluateOrDefault (
634- evaluator, SemanticDeclAvailabilityRequest {parent}, inherited);
640+ evaluator, DeclRuntimeAvailabilityRequest {parent}, inherited);
635641 }
636642
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;
644-
645- return SemanticDeclAvailability::PotentiallyAvailable;
646- }
643+ // If the inherited semantic availability is already maximally unavailable
644+ // then skip computing unavailability for this declaration.
645+ if (inherited == DeclRuntimeAvailability::AlwaysUnavailableABICompatible)
646+ return DeclRuntimeAvailability::AlwaysUnavailableABICompatible;
647647
648- bool Decl::isSemanticallyUnavailable () const {
649- auto availability = evaluateOrDefault (
650- getASTContext ().evaluator , SemanticDeclAvailabilityRequest{this },
651- SemanticDeclAvailability::PotentiallyAvailable);
652- return availability != SemanticDeclAvailability::PotentiallyAvailable;
648+ auto availability = getDeclRuntimeAvailability (decl);
649+ return std::max (inherited, availability);
653650}
654651
655652bool Decl::isUnreachableAtRuntime () const {
656653 auto availability = evaluateOrDefault (
657- getASTContext ().evaluator , SemanticDeclAvailabilityRequest{this },
658- SemanticDeclAvailability::PotentiallyAvailable);
659- return availability == SemanticDeclAvailability::CompletelyUnavailable;
654+ getASTContext ().evaluator , DeclRuntimeAvailabilityRequest{this },
655+ DeclRuntimeAvailability::PotentiallyAvailable);
656+ return availability ==
657+ DeclRuntimeAvailability::AlwaysUnavailableABICompatible;
660658}
661659
662660static UnavailableDeclOptimization
@@ -859,8 +857,6 @@ std::optional<llvm::VersionTuple> SemanticAvailableAttr::getIntroduced() const {
859857
860858std::optional<AvailabilityRange>
861859SemanticAvailableAttr::getIntroducedRange (const ASTContext &Ctx) const {
862- DEBUG_ASSERT (getDomain ().isActive (Ctx));
863-
864860 auto *attr = getParsedAttr ();
865861 if (!attr->getRawIntroduced ().has_value ()) {
866862 // For versioned domains, an "introduced:" version is always required to
@@ -899,8 +895,6 @@ std::optional<llvm::VersionTuple> SemanticAvailableAttr::getDeprecated() const {
899895
900896std::optional<AvailabilityRange>
901897SemanticAvailableAttr::getDeprecatedRange (const ASTContext &Ctx) const {
902- DEBUG_ASSERT (getDomain ().isActive (Ctx));
903-
904898 auto *attr = getParsedAttr ();
905899 if (!attr->getRawDeprecated ().has_value ()) {
906900 // Regardless of the whether the domain supports versions or not, an
@@ -930,8 +924,6 @@ std::optional<llvm::VersionTuple> SemanticAvailableAttr::getObsoleted() const {
930924
931925std::optional<AvailabilityRange>
932926SemanticAvailableAttr::getObsoletedRange (const ASTContext &Ctx) const {
933- DEBUG_ASSERT (getDomain ().isActive (Ctx));
934-
935927 auto *attr = getParsedAttr ();
936928
937929 // Obsoletion always requires a version.
0 commit comments