@@ -541,8 +541,10 @@ std::optional<SemanticAvailableAttr> Decl::getUnavailableAttr() const {
541
541
return std::nullopt;
542
542
}
543
543
544
+ // / Returns the mutually exclusive root platform domains that must all be
545
+ // / unavailable in order for a declaration to be unavailable at runtime.
544
546
static llvm::SmallSetVector<AvailabilityDomain, 2 >
545
- availabilityDomainsForABICompatibility (const ASTContext &ctx) {
547
+ getRootTargetDomains (const ASTContext &ctx) {
546
548
llvm::SmallSetVector<AvailabilityDomain, 2 > domains;
547
549
548
550
// Regardless of target platform, binaries built for Embedded do not require
@@ -551,83 +553,132 @@ availabilityDomainsForABICompatibility(const ASTContext &ctx) {
551
553
return domains;
552
554
553
555
if (auto targetDomain = AvailabilityDomain::forTargetPlatform (ctx))
554
- domains.insert (targetDomain->getABICompatibilityDomain ());
556
+ domains.insert (targetDomain->getRootDomain ());
555
557
556
558
if (auto variantDomain = AvailabilityDomain::forTargetVariantPlatform (ctx))
557
- domains.insert (variantDomain->getABICompatibilityDomain ());
559
+ domains.insert (variantDomain->getRootDomain ());
558
560
559
561
return domains;
560
562
}
561
563
562
564
static bool constraintIndicatesRuntimeUnavailability (
563
565
const AvailabilityConstraint &constraint, const ASTContext &ctx) {
566
+ std::optional<CustomAvailabilityDomain::Kind> customDomainKind;
567
+ if (auto customDomain = constraint.getDomain ().getCustomDomain ())
568
+ customDomainKind = customDomain->getKind ();
569
+
564
570
switch (constraint.getReason ()) {
565
- case AvailabilityConstraint::Reason::UnconditionallyUnavailable: {
571
+ case AvailabilityConstraint::Reason::UnconditionallyUnavailable:
572
+ if (customDomainKind)
573
+ return customDomainKind == CustomAvailabilityDomain::Kind::Enabled;
566
574
return true ;
567
- }
568
- case AvailabilityConstraint::Reason::UnavailableForDeployment:
569
575
case AvailabilityConstraint::Reason::Obsoleted:
576
+ case AvailabilityConstraint::Reason::UnavailableForDeployment:
577
+ return false ;
570
578
case AvailabilityConstraint::Reason::PotentiallyUnavailable:
579
+ if (customDomainKind)
580
+ return customDomainKind == CustomAvailabilityDomain::Kind::Disabled;
571
581
return false ;
572
582
}
573
583
}
574
584
575
- // / Computes the `DeclRuntimeAvailability` value for `decl`.
576
- static DeclRuntimeAvailability getDeclRuntimeAvailability (const Decl *decl) {
585
+ // / Returns true if a decl that is unavailable in the given domain must still be
586
+ // / emitted to preserve load time ABI compatibility.
587
+ static bool
588
+ domainRequiresABICompatibleUnavailableDecls (AvailabilityDomain domain,
589
+ const ASTContext &ctx) {
590
+ // FIXME: [availability] Restrict ABI compatible unavailable decls to modules
591
+ // compiled with macOS, iOS, watchOS, tvOS, or visionOS target triples. For
592
+ // other targets, unavailable code should always be stripped from binaries.
593
+ return domain.isUniversal () || domain.isPlatform ();
594
+ }
595
+
596
+ // / Computes the `DeclRuntimeAvailability` value for `decl` in isolation.
597
+ static DeclRuntimeAvailability
598
+ computeDeclRuntimeAvailability (const Decl *decl) {
577
599
// Don't trust unavailability on declarations from Clang modules.
578
600
if (isa<ClangModuleUnit>(decl->getDeclContext ()->getModuleScopeContext ()))
579
601
return DeclRuntimeAvailability::PotentiallyAvailable;
580
602
581
- // Check whether the decl is unavailable at all.
582
- if (!decl->isUnavailable ())
583
- return DeclRuntimeAvailability::PotentiallyAvailable;
584
-
585
603
auto &ctx = decl->getASTContext ();
586
- auto compatibilityDomains = availabilityDomainsForABICompatibility (ctx);
587
- auto potentiallyAvailableDomains = compatibilityDomains ;
604
+ auto rootTargetDomains = getRootTargetDomains (ctx);
605
+ auto remainingTargetDomains = rootTargetDomains ;
588
606
589
607
AvailabilityConstraintFlags flags;
590
608
591
609
// Semantic availability was already computed separately for any enclosing
592
610
// extension.
593
611
flags |= AvailabilityConstraintFlag::SkipEnclosingExtension;
594
612
595
- // FIXME: [availability] Inactive domains have to be included because iOS
596
- // availability is considered inactive when compiling a zippered module.
613
+ // FIXME: [availability] Replace IncludeAllDomains with a RuntimeAvailability
614
+ // flag that includes the target variant constraints and keeps all constraints
615
+ // from active platforms.
597
616
flags |= AvailabilityConstraintFlag::IncludeAllDomains;
598
617
599
618
auto constraints = getAvailabilityConstraintsForDecl (
600
619
decl, AvailabilityContext::forInliningTarget (ctx), flags);
601
620
621
+ // First, collect the unavailable domains from the constraints.
622
+ llvm::SmallVector<AvailabilityDomain, 8 > unavailableDomains;
602
623
for (auto constraint : constraints) {
603
- if (!constraintIndicatesRuntimeUnavailability (constraint, ctx))
624
+ if (constraintIndicatesRuntimeUnavailability (constraint, ctx))
625
+ unavailableDomains.push_back (constraint.getDomain ());
626
+ }
627
+
628
+ // Check whether there are any available attributes that would make the
629
+ // decl available in descendants of the unavailable domains.
630
+ for (auto attr :
631
+ decl->getSemanticAvailableAttrs (/* includingInactive=*/ false )) {
632
+ auto domain = attr.getDomain ();
633
+ if (llvm::is_contained (unavailableDomains, domain))
604
634
continue ;
605
635
636
+ llvm::erase_if (unavailableDomains, [domain](auto unavailableDomain) {
637
+ return unavailableDomain.contains (domain);
638
+ });
639
+ }
640
+
641
+ // Check the remaining unavailable domains to see if the requirements for
642
+ // runtime unreachability are met.
643
+ auto result = DeclRuntimeAvailability::PotentiallyAvailable;
644
+ for (auto domain : unavailableDomains) {
606
645
// Check whether the constraint is from a relevant domain.
607
- auto domain = constraint.getDomain ();
608
- bool isCompabilityDomainDescendant =
609
- llvm::find_if (compatibilityDomains,
610
- [&domain](AvailabilityDomain compatibilityDomain) {
611
- return compatibilityDomain.contains (domain);
612
- }) != compatibilityDomains.end ();
613
-
614
- if (!domain.isActive (ctx) && !isCompabilityDomainDescendant)
646
+ bool isTargetDomain = rootTargetDomains.contains (domain);
647
+ if (!domain.isActive (ctx) && !isTargetDomain)
615
648
continue ;
616
649
617
- if (isCompabilityDomainDescendant) {
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 ;
650
+ if (!domain.isRoot ())
651
+ continue ;
652
+
653
+ // We've found an unavailable target domain. If all the target domains are
654
+ // unavailable then the decl is unreachable at runtime.
655
+ if (isTargetDomain) {
656
+ remainingTargetDomains.remove (domain);
657
+ if (remainingTargetDomains.empty ())
658
+ result = DeclRuntimeAvailability::AlwaysUnavailableABICompatible;
659
+
660
+ continue ;
623
661
}
624
662
625
- // Either every compatibility domain has been proven unavailable or this
626
- // constraint proves runtime unavailability on its own.
627
- return DeclRuntimeAvailability::AlwaysUnavailableABICompatible;
663
+ // We've found a single unavailable domain that alone proves the decl is
664
+ // unreachable at runtime. It may still be required at load time, though.
665
+ if (domainRequiresABICompatibleUnavailableDecls (domain, ctx)) {
666
+ result = DeclRuntimeAvailability::AlwaysUnavailableABICompatible;
667
+ continue ;
668
+ }
669
+
670
+ return DeclRuntimeAvailability::AlwaysUnavailable;
628
671
}
629
672
630
- return DeclRuntimeAvailability::PotentiallyAvailable;
673
+ return result;
674
+ }
675
+
676
+ // / Determines the `DeclRuntimeAvailability` value for `decl` via
677
+ // / `DeclRuntimeAvailabilityRequest`.
678
+ static DeclRuntimeAvailability getDeclRuntimeAvailability (const Decl *decl) {
679
+ return evaluateOrDefault (decl->getASTContext ().evaluator ,
680
+ DeclRuntimeAvailabilityRequest{decl},
681
+ DeclRuntimeAvailability::PotentiallyAvailable);
631
682
}
632
683
633
684
DeclRuntimeAvailability
@@ -636,24 +687,20 @@ DeclRuntimeAvailabilityRequest::evaluate(Evaluator &evaluator,
636
687
auto inherited = DeclRuntimeAvailability::PotentiallyAvailable;
637
688
if (auto *parent =
638
689
AvailabilityInference::parentDeclForInferredAvailability (decl)) {
639
- inherited = evaluateOrDefault (
640
- evaluator, DeclRuntimeAvailabilityRequest{parent}, inherited);
690
+ inherited = getDeclRuntimeAvailability (parent);
641
691
}
642
692
643
- // If the inherited semantic availability is already maximally unavailable
693
+ // If the inherited runtime availability is already maximally unavailable
644
694
// then skip computing unavailability for this declaration.
645
- if (inherited == DeclRuntimeAvailability::AlwaysUnavailableABICompatible )
646
- return DeclRuntimeAvailability::AlwaysUnavailableABICompatible ;
695
+ if (inherited == DeclRuntimeAvailability::AlwaysUnavailable )
696
+ return DeclRuntimeAvailability::AlwaysUnavailable ;
647
697
648
- auto availability = getDeclRuntimeAvailability (decl);
698
+ auto availability = computeDeclRuntimeAvailability (decl);
649
699
return std::max (inherited, availability);
650
700
}
651
701
652
702
bool Decl::isUnreachableAtRuntime () const {
653
- auto availability = evaluateOrDefault (
654
- getASTContext ().evaluator , DeclRuntimeAvailabilityRequest{this },
655
- DeclRuntimeAvailability::PotentiallyAvailable);
656
- return availability ==
703
+ return getDeclRuntimeAvailability (this ) >=
657
704
DeclRuntimeAvailability::AlwaysUnavailableABICompatible;
658
705
}
659
706
@@ -666,13 +713,15 @@ getEffectiveUnavailableDeclOptimization(ASTContext &ctx) {
666
713
}
667
714
668
715
bool Decl::isAvailableDuringLowering () const {
669
- // Unconditionally unavailable declarations should be skipped during lowering
670
- // when -unavailable-decl-optimization=complete is specified.
716
+ auto availability = getDeclRuntimeAvailability ( this );
717
+
671
718
if (getEffectiveUnavailableDeclOptimization (getASTContext ()) !=
672
719
UnavailableDeclOptimization::Complete)
673
- return true ;
720
+ return availability < DeclRuntimeAvailability::AlwaysUnavailable ;
674
721
675
- return !isUnreachableAtRuntime ();
722
+ // All unreachable declarations should be skipped during lowering
723
+ // when -unavailable-decl-optimization=complete is specified.
724
+ return availability < DeclRuntimeAvailability::AlwaysUnavailableABICompatible;
676
725
}
677
726
678
727
bool Decl::requiresUnavailableDeclABICompatibilityStubs () const {
0 commit comments