Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions include/swift/AST/AvailabilityConstraint.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,14 @@ std::optional<AvailabilityConstraint> getAvailabilityConstraintForDeclInDomain(
const Decl *decl, const AvailabilityContext &context,
AvailabilityDomain domain,
AvailabilityConstraintFlags flags = std::nullopt);

/// Computes the set of constraints that indicate whether a decl is "runtime
/// unavailable" (can never be reached at runtime) and adds the domain for each
/// of those constraints to the \p domains vector.
void getRuntimeUnavailableDomains(
const DeclAvailabilityConstraints &constraints,
llvm::SmallVectorImpl<AvailabilityDomain> &domains, const ASTContext &ctx);

} // end namespace swift

namespace llvm {
Expand Down
30 changes: 5 additions & 25 deletions lib/AST/Availability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -574,27 +574,6 @@ getRootTargetDomains(const ASTContext &ctx) {
return domains;
}

static bool constraintIndicatesRuntimeUnavailability(
const AvailabilityConstraint &constraint, const ASTContext &ctx) {
std::optional<CustomAvailabilityDomain::Kind> customDomainKind;
if (auto customDomain = constraint.getDomain().getCustomDomain())
customDomainKind = customDomain->getKind();

switch (constraint.getReason()) {
case AvailabilityConstraint::Reason::UnavailableUnconditionally:
if (customDomainKind)
return customDomainKind == CustomAvailabilityDomain::Kind::Enabled;
return true;
case AvailabilityConstraint::Reason::UnavailableObsolete:
case AvailabilityConstraint::Reason::UnavailableUnintroduced:
return false;
case AvailabilityConstraint::Reason::Unintroduced:
if (customDomainKind)
return customDomainKind == CustomAvailabilityDomain::Kind::Disabled;
return false;
}
}

/// Returns true if a decl that is unavailable in the given domain must still be
/// emitted to preserve load time ABI compatibility.
static bool
Expand Down Expand Up @@ -633,10 +612,7 @@ computeDeclRuntimeAvailability(const Decl *decl) {

// First, collect the unavailable domains from the constraints.
llvm::SmallVector<AvailabilityDomain, 8> unavailableDomains;
for (auto constraint : constraints) {
if (constraintIndicatesRuntimeUnavailability(constraint, ctx))
unavailableDomains.push_back(constraint.getDomain());
}
getRuntimeUnavailableDomains(constraints, unavailableDomains, ctx);

// Check whether there are any available attributes that would make the
// decl available in descendants of the unavailable domains.
Expand All @@ -647,6 +623,10 @@ computeDeclRuntimeAvailability(const Decl *decl) {
continue;

llvm::erase_if(unavailableDomains, [domain](auto unavailableDomain) {
// Unavailability in '*' cannot be superseded by an @available attribute
// for a more specific availability domain.
if (unavailableDomain.isUniversal())
return false;
return unavailableDomain.contains(domain);
});
}
Expand Down
30 changes: 30 additions & 0 deletions lib/AST/AvailabilityConstraint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,3 +322,33 @@ swift::getAvailabilityConstraintForDeclInDomain(

return std::nullopt;
}

static bool constraintIndicatesRuntimeUnavailability(
const AvailabilityConstraint &constraint, const ASTContext &ctx) {
std::optional<CustomAvailabilityDomain::Kind> customDomainKind;
if (auto customDomain = constraint.getDomain().getCustomDomain())
customDomainKind = customDomain->getKind();

switch (constraint.getReason()) {
case AvailabilityConstraint::Reason::UnavailableUnconditionally:
if (customDomainKind)
return customDomainKind == CustomAvailabilityDomain::Kind::Enabled;
return true;
case AvailabilityConstraint::Reason::UnavailableObsolete:
case AvailabilityConstraint::Reason::UnavailableUnintroduced:
return false;
case AvailabilityConstraint::Reason::Unintroduced:
if (customDomainKind)
return customDomainKind == CustomAvailabilityDomain::Kind::Disabled;
return false;
}
}

void swift::getRuntimeUnavailableDomains(
const DeclAvailabilityConstraints &constraints,
llvm::SmallVectorImpl<AvailabilityDomain> &domains, const ASTContext &ctx) {
for (auto constraint : constraints) {
if (constraintIndicatesRuntimeUnavailability(constraint, ctx))
domains.push_back(constraint.getDomain());
}
}
34 changes: 24 additions & 10 deletions test/SILGen/unavailable_decl_custom_domain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,15 @@
// RUN: -define-enabled-availability-domain EnabledDomain \
// RUN: -define-disabled-availability-domain DisabledDomain \
// RUN: -define-dynamic-availability-domain DynamicDomain \
// RUN: | %FileCheck %s

// RUN: %target-swift-emit-silgen -module-name Test %s -verify \
// RUN: -enable-experimental-feature CustomAvailability \
// RUN: -define-enabled-availability-domain EnabledDomain \
// RUN: -define-disabled-availability-domain DisabledDomain \
// RUN: -define-dynamic-availability-domain DynamicDomain \
// RUN: -unavailable-decl-optimization=stub \
// RUN: | %FileCheck %s
// RUN: | %FileCheck %s --check-prefixes=CHECK,CHECK-NOOPT

// RUN: %target-swift-emit-silgen -module-name Test %s -verify \
// RUN: -enable-experimental-feature CustomAvailability \
// RUN: -define-enabled-availability-domain EnabledDomain \
// RUN: -define-disabled-availability-domain DisabledDomain \
// RUN: -define-dynamic-availability-domain DynamicDomain \
// RUN: -unavailable-decl-optimization=complete \
// RUN: | %FileCheck %s
// RUN: | %FileCheck %s --check-prefixes=CHECK,CHECK-OPT

// REQUIRES: swift_feature_CustomAvailability

Expand Down Expand Up @@ -84,3 +76,25 @@ public func availableInEnabledAndDisabledDomain() { }
@available(DisabledDomain)
@available(EnabledDomain)
public func availableInDisabledAndEnabledDomain() { }

// CHECK-NOOPT: s4Test49availableInEnabledDomainAndUnavailableUniversallyyyF
// CHECK-OPT-NOT: s4Test49availableInEnabledDomainAndUnavailableUniversallyyyF
@available(*, unavailable)
@available(EnabledDomain)
public func availableInEnabledDomainAndUnavailableUniversally() { }

// CHECK-NOT: s4Test40unavailableInEnabledDomainAndUniversallyyyF
@available(*, unavailable)
@available(EnabledDomain, unavailable)
public func unavailableInEnabledDomainAndUniversally() { }

// CHECK-NOT: s4Test50availableInDisabledDomainAndUnavailableUniversallyyyF
@available(*, unavailable)
@available(DisabledDomain)
public func availableInDisabledDomainAndUnavailableUniversally() { }

// CHECK-NOOPT: s4Test41unavailableInDisabledDomainAndUniversallyyyF
// CHECK-OPT-NOT: s4Test41unavailableInDisabledDomainAndUniversallyyyF
@available(*, unavailable)
@available(DisabledDomain, unavailable)
public func unavailableInDisabledDomainAndUniversally() { }
8 changes: 8 additions & 0 deletions test/SILGen/unavailable_decl_optimization_stub.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ public func unavailableFunc() -> S {
return S()
}

// CHECK-LABEL: sil{{.*}}@$s4Test33unavailableFuncIntroducedInSwift5yyF
// CHECK: [[FNREF:%.*]] = function_ref @$[[DIAGNOSEFN:(ss31_diagnoseUnavailableCodeReacheds5NeverOyF|ss31_diagnoseUnavailableCodeReacheds5NeverOyFTwb)]] : $@convention(thin) () -> Never
// CHECK-NEXT: [[APPLY:%.*]] = apply [[FNREF]]()
// CHECK: } // end sil function '$s4Test33unavailableFuncIntroducedInSwift5yyF'
@available(*, unavailable)
@available(swift 5)
public func unavailableFuncIntroducedInSwift5() { }

// CHECK-LABEL: sil{{.*}}@$s4Test025unavailableFuncWithNestedC0yyF
// CHECK: [[FNREF:%.*]] = function_ref @$[[DIAGNOSEFN:(ss31_diagnoseUnavailableCodeReacheds5NeverOyF|ss31_diagnoseUnavailableCodeReacheds5NeverOyFTwb)]] : $@convention(thin) () -> Never
// CHECK-NEXT: [[APPLY:%.*]] = apply [[FNREF]]()
Expand Down
8 changes: 8 additions & 0 deletions test/SILGen/unavailable_decl_optimization_stub_macos.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ public func unavailableFunc() {}
@available(macOS, unavailable)
public func unavailableOnMacOSFunc() {}

// CHECK-LABEL: sil{{.*}}@$s4Test36unavailableFuncWithMacOSIntroductionyyF
// CHECK: [[FNREF:%.*]] = function_ref @$ss31_diagnoseUnavailableCodeReacheds5NeverOyFTwb : $@convention(thin) () -> Never
// CHECK-NEXT: [[APPLY:%.*]] = apply [[FNREF]]()
// CHECK: } // end sil function '$s4Test36unavailableFuncWithMacOSIntroductionyyF'
@available(*, unavailable)
@available(macOS 12.0, *)
public func unavailableFuncWithMacOSIntroduction() {}

// CHECK-LABEL: sil{{.*}}@$s4Test31unavailableOnMacOSExtensionFuncyyF
// CHECK-NOT: _diagnoseUnavailableCodeReached
// CHECK: } // end sil function '$s4Test31unavailableOnMacOSExtensionFuncyyF'
Expand Down