@@ -563,28 +563,43 @@ getRootTargetDomains(const ASTContext &ctx) {
563
563
564
564
static bool constraintIndicatesRuntimeUnavailability (
565
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
+
566
570
switch (constraint.getReason ()) {
567
- case AvailabilityConstraint::Reason::UnconditionallyUnavailable: {
571
+ case AvailabilityConstraint::Reason::UnconditionallyUnavailable:
572
+ if (customDomainKind)
573
+ return customDomainKind == CustomAvailabilityDomain::Kind::Enabled;
568
574
return true ;
569
- }
570
- case AvailabilityConstraint::Reason::UnavailableForDeployment:
571
575
case AvailabilityConstraint::Reason::Obsoleted:
576
+ case AvailabilityConstraint::Reason::UnavailableForDeployment:
577
+ return false ;
572
578
case AvailabilityConstraint::Reason::PotentiallyUnavailable:
579
+ if (customDomainKind)
580
+ return customDomainKind == CustomAvailabilityDomain::Kind::Disabled;
573
581
return false ;
574
582
}
575
583
}
576
584
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
+
577
596
// / Computes the `DeclRuntimeAvailability` value for `decl` in isolation.
578
597
static DeclRuntimeAvailability
579
598
computeDeclRuntimeAvailability (const Decl *decl) {
580
599
// Don't trust unavailability on declarations from Clang modules.
581
600
if (isa<ClangModuleUnit>(decl->getDeclContext ()->getModuleScopeContext ()))
582
601
return DeclRuntimeAvailability::PotentiallyAvailable;
583
602
584
- // Check whether the decl is unavailable at all.
585
- if (!decl->isUnavailable ())
586
- return DeclRuntimeAvailability::PotentiallyAvailable;
587
-
588
603
auto &ctx = decl->getASTContext ();
589
604
auto rootTargetDomains = getRootTargetDomains (ctx);
590
605
auto remainingTargetDomains = rootTargetDomains;
@@ -595,41 +610,67 @@ computeDeclRuntimeAvailability(const Decl *decl) {
595
610
// extension.
596
611
flags |= AvailabilityConstraintFlag::SkipEnclosingExtension;
597
612
598
- // FIXME: [availability] Inactive domains have to be included because iOS
599
- // 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.
600
616
flags |= AvailabilityConstraintFlag::IncludeAllDomains;
601
617
602
618
auto constraints = getAvailabilityConstraintsForDecl (
603
619
decl, AvailabilityContext::forInliningTarget (ctx), flags);
604
620
621
+ // First, collect the unavailable domains from the constraints.
622
+ llvm::SmallVector<AvailabilityDomain, 8 > unavailableDomains;
605
623
for (auto constraint : constraints) {
606
- 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))
607
634
continue ;
608
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) {
609
645
// Check whether the constraint is from a relevant domain.
610
- auto domain = constraint.getDomain ();
611
646
bool isTargetDomain = rootTargetDomains.contains (domain);
612
-
613
647
if (!domain.isActive (ctx) && !isTargetDomain)
614
648
continue ;
615
649
616
650
if (!domain.isRoot ())
617
651
continue ;
618
652
653
+ // We've found an unavailable target domain. If all the target domains are
654
+ // unavailable then the decl is unreachable at runtime.
619
655
if (isTargetDomain) {
620
- // If the decl is still potentially available in some compatibility
621
- // domain, keep looking at the remaining constraints.
622
656
remainingTargetDomains.remove (domain);
623
- if (!remainingTargetDomains.empty ())
624
- continue ;
657
+ if (remainingTargetDomains.empty ())
658
+ result = DeclRuntimeAvailability::AlwaysUnavailableABICompatible;
659
+
660
+ continue ;
625
661
}
626
662
627
- // Either every compatibility domain has been proven unavailable or this
628
- // constraint proves runtime unavailability on its own.
629
- 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;
630
671
}
631
672
632
- return DeclRuntimeAvailability::PotentiallyAvailable ;
673
+ return result ;
633
674
}
634
675
635
676
// / Determines the `DeclRuntimeAvailability` value for `decl` via
@@ -651,8 +692,8 @@ DeclRuntimeAvailabilityRequest::evaluate(Evaluator &evaluator,
651
692
652
693
// If the inherited runtime availability is already maximally unavailable
653
694
// then skip computing unavailability for this declaration.
654
- if (inherited == DeclRuntimeAvailability::AlwaysUnavailableABICompatible )
655
- return DeclRuntimeAvailability::AlwaysUnavailableABICompatible ;
695
+ if (inherited == DeclRuntimeAvailability::AlwaysUnavailable )
696
+ return DeclRuntimeAvailability::AlwaysUnavailable ;
656
697
657
698
auto availability = computeDeclRuntimeAvailability (decl);
658
699
return std::max (inherited, availability);
@@ -676,7 +717,7 @@ bool Decl::isAvailableDuringLowering() const {
676
717
677
718
if (getEffectiveUnavailableDeclOptimization (getASTContext ()) !=
678
719
UnavailableDeclOptimization::Complete)
679
- return true ;
720
+ return availability < DeclRuntimeAvailability::AlwaysUnavailable ;
680
721
681
722
// All unreachable declarations should be skipped during lowering
682
723
// when -unavailable-decl-optimization=complete is specified.
0 commit comments