AST: Introduce an "always enabled" custom availability domain kind.

An always enabled availability domain is implicitly available in all contexts,
so uses of declarations that are marked as `@available` in the domain are never
rejected. This is useful for an availability domain representing a feature flag
that has become permanently enabled.

Partially resolves rdar://157593409.
This commit is contained in:
Allan Shortlidge
2025-09-10 10:16:29 -07:00
parent 8c5acc0bb7
commit 0647da5416
13 changed files with 242 additions and 22 deletions

View File

@@ -226,11 +226,12 @@ public:
/// Returns true if this domain is considered active in the current
/// compilation context.
bool isActive(const ASTContext &ctx) const;
bool isActive(const ASTContext &ctx, bool forTargetVariant = false) const;
/// Returns true if this domain is a platform domain and is considered active
/// in the current compilation context.
bool isActivePlatform(const ASTContext &ctx) const;
bool isActivePlatform(const ASTContext &ctx,
bool forTargetVariant = false) const;
/// Returns the domain's minimum available range for type checking. For
/// example, for the domain of the platform that compilation is targeting,
@@ -332,6 +333,9 @@ public:
enum class Kind {
/// A domain that is known to be enabled at compile time.
Enabled,
/// A domain that is known to be enabled at compile time and is also assumed
/// to be enabled for all deployments.
AlwaysEnabled,
/// A domain that is known to be disabled at compile time.
Disabled,
/// A domain with an enablement state that must be queried at runtime.

View File

@@ -615,6 +615,8 @@ public:
struct CustomAvailabilityDomains {
/// Domains defined with `-define-enabled-availability-domain=`.
llvm::SmallVector<std::string> EnabledDomains;
/// Domains defined with `-define-always-enabled-availability-domain=`.
llvm::SmallVector<std::string> AlwaysEnabledDomains;
/// Domains defined with `-define-disabled-availability-domain=`.
llvm::SmallVector<std::string> DisabledDomains;
/// Domains defined with `-define-dynamic-availability-domain=`.

View File

@@ -576,6 +576,14 @@ def define_enabled_availability_domain : Separate<["-"], "define-enabled-availab
HelpText<"Defines a custom availability domain that is available at compile time">,
MetaVarName<"<domain>">;
def define_always_enabled_availability_domain
: Separate<["-"], "define-always-enabled-availability-domain">,
Flags<[HelpHidden, FrontendOption, NoInteractiveOption,
ModuleInterfaceOptionIgnorable]>,
HelpText<"Defines a custom availability domain that is available for all "
"deployments">,
MetaVarName<"<domain>">;
def define_disabled_availability_domain : Separate<["-"], "define-disabled-availability-domain">,
Flags<[HelpHidden, FrontendOption, NoInteractiveOption, ModuleInterfaceOptionIgnorable]>,
HelpText<"Defines a custom availability domain that is unavailable at compile time">,

View File

@@ -204,11 +204,15 @@ getAvailabilityConstraintForAttr(const Decl *decl,
auto &ctx = decl->getASTContext();
auto domain = attr.getDomain();
auto deploymentRange = domain.getDeploymentRange(ctx);
bool domainSupportsRefinement = domain.supportsContextRefinement();
std::optional<AvailabilityRange> availableRange =
domainSupportsRefinement ? context.getAvailabilityRange(domain, ctx)
: deploymentRange;
// Compute the available range in the given context. If there is no explicit
// range defined by the context, use the deployment range as fallback.
std::optional<AvailabilityRange> availableRange;
if (domainSupportsRefinement)
availableRange = context.getAvailabilityRange(domain, ctx);
if (!availableRange)
availableRange = domain.getDeploymentRange(ctx);
// Is the decl obsoleted in this context?
if (auto obsoletedRange = attr.getObsoletedRange(ctx)) {
@@ -323,24 +327,78 @@ swift::getAvailabilityConstraintForDeclInDomain(
return std::nullopt;
}
/// Returns true if unsatisfied `@available(..., unavailable)` constraints for
/// \p domain make code unreachable at runtime
static bool
domainCanBeUnconditionallyUnavailableAtRuntime(AvailabilityDomain domain,
const ASTContext &ctx) {
switch (domain.getKind()) {
case AvailabilityDomain::Kind::Universal:
return true;
case AvailabilityDomain::Kind::Platform:
if (ctx.LangOpts.TargetVariant &&
domain.isActive(ctx, /*forTargetVariant=*/true))
return true;
return domain.isActive(ctx);
case AvailabilityDomain::Kind::SwiftLanguage:
case AvailabilityDomain::Kind::PackageDescription:
return false;
case AvailabilityDomain::Kind::Embedded:
return ctx.LangOpts.hasFeature(Feature::Embedded);
case AvailabilityDomain::Kind::Custom:
switch (domain.getCustomDomain()->getKind()) {
case CustomAvailabilityDomain::Kind::Enabled:
case CustomAvailabilityDomain::Kind::AlwaysEnabled:
return true;
case CustomAvailabilityDomain::Kind::Disabled:
case CustomAvailabilityDomain::Kind::Dynamic:
return false;
}
}
}
/// Returns true if unsatisfied introduction constraints for \p domain make
/// code unreachable at runtime.
static bool
domainIsUnavailableAtRuntimeIfUnintroduced(AvailabilityDomain domain,
const ASTContext &ctx) {
switch (domain.getKind()) {
case AvailabilityDomain::Kind::Universal:
case AvailabilityDomain::Kind::Platform:
case AvailabilityDomain::Kind::SwiftLanguage:
case AvailabilityDomain::Kind::PackageDescription:
return false;
case AvailabilityDomain::Kind::Embedded:
return !ctx.LangOpts.hasFeature(Feature::Embedded);
case AvailabilityDomain::Kind::Custom:
switch (domain.getCustomDomain()->getKind()) {
case CustomAvailabilityDomain::Kind::Enabled:
case CustomAvailabilityDomain::Kind::AlwaysEnabled:
case CustomAvailabilityDomain::Kind::Dynamic:
return false;
case CustomAvailabilityDomain::Kind::Disabled:
return true;
}
}
}
static bool constraintIndicatesRuntimeUnavailability(
const AvailabilityConstraint &constraint, const ASTContext &ctx) {
std::optional<CustomAvailabilityDomain::Kind> customDomainKind;
if (auto customDomain = constraint.getDomain().getCustomDomain())
customDomainKind = customDomain->getKind();
auto domain = constraint.getDomain();
switch (constraint.getReason()) {
case AvailabilityConstraint::Reason::UnavailableUnconditionally:
if (customDomainKind)
return customDomainKind == CustomAvailabilityDomain::Kind::Enabled;
return true;
return domainCanBeUnconditionallyUnavailableAtRuntime(domain, ctx);
case AvailabilityConstraint::Reason::UnavailableObsolete:
case AvailabilityConstraint::Reason::UnavailableUnintroduced:
return false;
case AvailabilityConstraint::Reason::Unintroduced:
if (customDomainKind)
return customDomainKind == CustomAvailabilityDomain::Kind::Disabled;
return false;
return domainIsUnavailableAtRuntimeIfUnintroduced(domain, ctx);
}
}

View File

@@ -33,6 +33,7 @@ getCustomDomainKind(clang::FeatureAvailKind featureAvailKind) {
return CustomAvailabilityDomain::Kind::Disabled;
case clang::FeatureAvailKind::Dynamic:
return CustomAvailabilityDomain::Kind::Dynamic;
// FIXME: [availability] Add support for AlwaysEnabled.
default:
llvm::report_fatal_error("unexpected kind");
}
@@ -53,6 +54,7 @@ customDomainForClangDecl(ValueDecl *decl) {
return nullptr;
// Check that the domain has a supported availability kind.
// FIXME: [availability] Add support for AlwaysEnabled.
switch (featureInfo.second.Kind) {
case clang::FeatureAvailKind::Available:
case clang::FeatureAvailKind::Unavailable:
@@ -181,7 +183,8 @@ bool AvailabilityDomain::supportsQueries() const {
}
}
bool AvailabilityDomain::isActive(const ASTContext &ctx) const {
bool AvailabilityDomain::isActive(const ASTContext &ctx,
bool forTargetVariant) const {
switch (getKind()) {
case Kind::Universal:
case Kind::SwiftLanguage:
@@ -189,7 +192,7 @@ bool AvailabilityDomain::isActive(const ASTContext &ctx) const {
case Kind::Embedded:
return true;
case Kind::Platform:
return isPlatformActive(getPlatformKind(), ctx.LangOpts);
return isPlatformActive(getPlatformKind(), ctx.LangOpts, forTargetVariant);
case Kind::Custom:
// For now, custom domains are always active but it's conceivable that in
// the future someone might want to define a domain but leave it inactive.
@@ -197,11 +200,12 @@ bool AvailabilityDomain::isActive(const ASTContext &ctx) const {
}
}
bool AvailabilityDomain::isActivePlatform(const ASTContext &ctx) const {
bool AvailabilityDomain::isActivePlatform(const ASTContext &ctx,
bool forTargetVariant) const {
if (!isPlatform())
return false;
return isActive(ctx);
return isActive(ctx, forTargetVariant);
}
static std::optional<llvm::VersionTuple>
@@ -224,8 +228,23 @@ getDeploymentVersion(const AvailabilityDomain &domain, const ASTContext &ctx) {
std::optional<AvailabilityRange>
AvailabilityDomain::getDeploymentRange(const ASTContext &ctx) const {
if (auto version = getDeploymentVersion(*this, ctx))
return AvailabilityRange{*version};
if (isVersioned()) {
if (auto version = getDeploymentVersion(*this, ctx))
return AvailabilityRange{*version};
return std::nullopt;
}
if (auto customDomain = getCustomDomain()) {
switch (customDomain->getKind()) {
case CustomAvailabilityDomain::Kind::AlwaysEnabled:
return AvailabilityRange::alwaysAvailable();
case CustomAvailabilityDomain::Kind::Enabled:
case CustomAvailabilityDomain::Kind::Disabled:
case CustomAvailabilityDomain::Kind::Dynamic:
return std::nullopt;
}
}
return std::nullopt;
}

View File

@@ -881,6 +881,7 @@ private:
switch (customDomain->getKind()) {
case CustomAvailabilityDomain::Kind::Enabled:
case CustomAvailabilityDomain::Kind::AlwaysEnabled:
return AvailabilityQuery::constant(domain, true);
case CustomAvailabilityDomain::Kind::Disabled:
return AvailabilityQuery::constant(domain, false);

View File

@@ -586,6 +586,7 @@ bool ArgsToFrontendOptionsConverter::computeAvailabilityDomains() {
for (const Arg *A :
Args.filtered_reverse(OPT_define_enabled_availability_domain,
OPT_define_always_enabled_availability_domain,
OPT_define_disabled_availability_domain,
OPT_define_dynamic_availability_domain)) {
std::string domain = A->getValue();
@@ -602,6 +603,8 @@ bool ArgsToFrontendOptionsConverter::computeAvailabilityDomains() {
auto &option = A->getOption();
if (option.matches(OPT_define_enabled_availability_domain))
Opts.AvailabilityDomains.EnabledDomains.emplace_back(domain);
if (option.matches(OPT_define_always_enabled_availability_domain))
Opts.AvailabilityDomains.AlwaysEnabledDomains.emplace_back(domain);
else if (option.matches(OPT_define_disabled_availability_domain))
Opts.AvailabilityDomains.DisabledDomains.emplace_back(domain);
else if (option.matches(OPT_define_dynamic_availability_domain))

View File

@@ -1455,6 +1455,9 @@ static void configureAvailabilityDomains(const ASTContext &ctx,
for (auto enabled : opts.AvailabilityDomains.EnabledDomains)
createAndInsertDomain(enabled, CustomAvailabilityDomain::Kind::Enabled);
for (auto alwaysEnabled : opts.AvailabilityDomains.AlwaysEnabledDomains)
createAndInsertDomain(alwaysEnabled,
CustomAvailabilityDomain::Kind::AlwaysEnabled);
for (auto disabled : opts.AvailabilityDomains.DisabledDomains)
createAndInsertDomain(disabled, CustomAvailabilityDomain::Kind::Disabled);
for (auto dynamic : opts.AvailabilityDomains.DynamicDomains)

View File

@@ -1,6 +1,7 @@
// RUN: %target-typecheck-verify-swift \
// RUN: -enable-experimental-feature CustomAvailability \
// RUN: -define-enabled-availability-domain EnabledDomain \
// RUN: -define-always-enabled-availability-domain AlwaysEnabledDomain \
// RUN: -define-disabled-availability-domain DisabledDomain \
// RUN: -define-dynamic-availability-domain DynamicDomain
@@ -11,9 +12,15 @@ func alwaysAvailable() { }
@available(EnabledDomain)
func availableInEnabledDomain() { }
@available(AlwaysEnabledDomain)
func availableInAlwaysEnabledDomain() { }
@available(EnabledDomain, unavailable)
func unavailableInEnabledDomain() { } // expected-note * {{'unavailableInEnabledDomain()' has been explicitly marked unavailable here}}
@available(AlwaysEnabledDomain, unavailable)
func unavailableInAlwaysEnabledDomain() { } // expected-note * {{'unavailableInAlwaysEnabledDomain()' has been explicitly marked unavailable here}}
@available(DisabledDomain, unavailable)
func unavailableInDisabledDomain() { } // expected-note * {{'unavailableInDisabledDomain()' has been explicitly marked unavailable here}}
@@ -41,7 +48,9 @@ func testDeployment() { // expected-note 3 {{add '@available' attribute to enclo
alwaysAvailable()
availableInEnabledDomain() // expected-error {{'availableInEnabledDomain()' is only available in EnabledDomain}}
// expected-note@-1 {{add 'if #available' version check}}
availableInAlwaysEnabledDomain()
unavailableInEnabledDomain() // expected-error {{'unavailableInEnabledDomain()' is unavailable}}
unavailableInAlwaysEnabledDomain() // expected-error {{'unavailableInAlwaysEnabledDomain()' is unavailable}}
unavailableInDisabledDomain() // expected-error {{'unavailableInDisabledDomain()' is unavailable}}
deprecatedInDynamicDomain() // expected-warning {{'deprecatedInDynamicDomain()' is deprecated: Use something else}}
unavailableInDynamicDomain() // expected-error {{'unavailableInDynamicDomain()' is unavailable}}
@@ -53,10 +62,14 @@ func testDeployment() { // expected-note 3 {{add '@available' attribute to enclo
availableAndUnavailableInEnabledDomain() // expected-error {{'availableAndUnavailableInEnabledDomain()' is unavailable}}
}
// FIXME: [availability] Test @inlinable functions.
func testIfAvailable(_ truthy: Bool) { // expected-note 9 {{add '@available' attribute to enclosing global function}}
if #available(EnabledDomain) { // expected-note {{enclosing scope here}}
availableInEnabledDomain()
availableInAlwaysEnabledDomain()
unavailableInEnabledDomain() // expected-error {{'unavailableInEnabledDomain()' is unavailable}}
unavailableInAlwaysEnabledDomain() // expected-error {{'unavailableInAlwaysEnabledDomain()' is unavailable}}
availableInDynamicDomain() // expected-error {{'availableInDynamicDomain()' is only available in DynamicDomain}}
// expected-note@-1 {{add 'if #available' version check}}
unavailableInDynamicDomain() // expected-error {{'unavailableInDynamicDomain()' is unavailable}}
@@ -133,6 +146,14 @@ func testIfAvailable(_ truthy: Bool) { // expected-note 9 {{add '@available' att
if #unavailable(EnabledDomain), #available(DynamicDomain) {
// expected-error@-1 {{#available and #unavailable cannot be in the same statement}}
}
if #available(AlwaysEnabledDomain) {
availableInAlwaysEnabledDomain()
unavailableInAlwaysEnabledDomain() // expected-error {{'unavailableInAlwaysEnabledDomain()' is unavailable}}
} else {
availableInAlwaysEnabledDomain()
unavailableInAlwaysEnabledDomain()
}
}
func testWhileAvailable() { // expected-note {{add '@available' attribute to enclosing global function}}
@@ -207,6 +228,18 @@ func testEnabledDomainUnavailable() { // expected-note {{add '@available' attrib
availableInUnknownDomain()
}
@available(AlwaysEnabledDomain)
func testAlwaysEnabledDomainAvailable() {
availableInAlwaysEnabledDomain()
unavailableInAlwaysEnabledDomain() // expected-error {{'unavailableInAlwaysEnabledDomain()' is unavailable}}
}
@available(AlwaysEnabledDomain, unavailable)
func testAlwaysEnabledDomainUnavailable() {
availableInAlwaysEnabledDomain()
unavailableInAlwaysEnabledDomain()
}
@available(*, unavailable)
func testUniversallyUnavailable() {
alwaysAvailable()
@@ -214,6 +247,9 @@ func testUniversallyUnavailable() {
// in contexts that are unavailable to broader domains
availableInEnabledDomain() // expected-error {{'availableInEnabledDomain()' is only available in EnabledDomain}}
// expected-note@-1 {{add 'if #available' version check}}
unavailableInEnabledDomain()
availableInAlwaysEnabledDomain()
unavailableInAlwaysEnabledDomain()
unavailableInDisabledDomain()
deprecatedInDynamicDomain() // expected-warning {{'deprecatedInDynamicDomain()' is deprecated: Use something else}}
availableInDynamicDomain() // expected-error {{'availableInDynamicDomain()' is only available in DynamicDomain}}

View File

@@ -1,12 +1,14 @@
// RUN: %target-swift-emit-irgen -module-name Test %s -verify \
// RUN: -enable-experimental-feature CustomAvailability \
// RUN: -define-enabled-availability-domain EnabledDomain \
// RUN: -define-always-enabled-availability-domain AlwaysEnabledDomain \
// RUN: -define-disabled-availability-domain DisabledDomain \
// RUN: -Onone | %FileCheck %s --check-prefixes=CHECK
// RUN: %target-swift-emit-irgen -module-name Test %s -verify \
// RUN: -enable-experimental-feature CustomAvailability \
// RUN: -define-enabled-availability-domain EnabledDomain \
// RUN: -define-always-enabled-availability-domain AlwaysEnabledDomain \
// RUN: -define-disabled-availability-domain DisabledDomain \
// RUN: -O | %FileCheck %s --check-prefixes=CHECK
@@ -29,6 +31,17 @@ public func ifAvailableEnabledDomain() {
}
}
// CHECK-LABEL: define {{.*}}swiftcc void @"$s4Test30ifAvailableAlwaysEnabledDomainyyF"()
// CHECK: call swiftcc void @always()
// CHECK-NOT: call swiftcc void @never()
public func ifAvailableAlwaysEnabledDomain() {
if #available(AlwaysEnabledDomain) {
always()
} else {
never()
}
}
// CHECK-LABEL: define {{.*}}swiftcc void @"$s4Test25ifAvailableDisabledDomainyyF"()
// CHECK-NOT: call swiftcc void @never()
// CHECK: call swiftcc void @always()
@@ -51,6 +64,17 @@ public func ifUnavailableEnabledDomain() {
}
}
// CHECK-LABEL: define {{.*}}swiftcc void @"$s4Test32ifUnavailableAlwaysEnabledDomainyyF"()
// CHECK-NOT: call swiftcc void @never()
// CHECK: call swiftcc void @always()
public func ifUnavailableAlwaysEnabledDomain() {
if #unavailable(EnabledDomain) {
never()
} else {
always()
}
}
// CHECK-LABEL: define {{.*}}swiftcc void @"$s4Test27ifUnavailableDisabledDomainyyF"()
// CHECK: call swiftcc void @always()
// CHECK-NOT: call swiftcc void @never()

View File

@@ -1,6 +1,7 @@
// RUN: %target-swift-emit-silgen -module-name Test %s -verify \
// RUN: -enable-experimental-feature CustomAvailability \
// RUN: -define-enabled-availability-domain EnabledDomain \
// RUN: -define-always-enabled-availability-domain AlwaysEnabledDomain \
// RUN: -define-disabled-availability-domain DisabledDomain \
// RUN: -define-dynamic-availability-domain DynamicDomain \
// RUN: | %FileCheck %s
@@ -13,6 +14,12 @@ public func availableInEnabledDomain() { }
@available(EnabledDomain, unavailable)
public func unavailableInEnabledDomain() { }
@available(AlwaysEnabledDomain)
public func availableInAlwaysEnabledDomain() { }
@available(AlwaysEnabledDomain, unavailable)
public func unavailableInAlwaysEnabledDomain() { }
@available(DisabledDomain)
public func availableInDisabledDomain() { }
@@ -63,6 +70,44 @@ public func testIfUnavailableEnabledDomain() {
}
// CHECK: end sil function '$s4Test30testIfUnavailableEnabledDomainyyF'
// CHECK-LABEL: sil{{.*}}$s4Test34testIfAvailableAlwaysEnabledDomainyyF : $@convention(thin) () -> ()
public func testIfAvailableAlwaysEnabledDomain() {
// CHECK: bb0:
// CHECK: [[PRED:%.*]] = integer_literal $Builtin.Int1, -1
// CHECK: cond_br [[PRED]], [[TRUE_BB:bb[0-9]+]], [[FALSE_BB:bb[0-9]+]]
// CHECK: [[TRUE_BB]]:
// CHECK: function_ref @$s4Test30availableInAlwaysEnabledDomainyyF
// CHECK: [[FALSE_BB]]:
// CHECK: function_ref @$s4Test32unavailableInAlwaysEnabledDomainyyF
if #available(AlwaysEnabledDomain) {
availableInAlwaysEnabledDomain()
} else {
unavailableInAlwaysEnabledDomain()
}
}
// CHECK: end sil function '$s4Test34testIfAvailableAlwaysEnabledDomainyyF'
// CHECK-LABEL: sil{{.*}}$s4Test36testIfUnavailableAlwaysEnabledDomainyyF : $@convention(thin) () -> ()
public func testIfUnavailableAlwaysEnabledDomain() {
// CHECK: bb0:
// CHECK: [[PRED:%.*]] = integer_literal $Builtin.Int1, 0
// CHECK: cond_br [[PRED]], [[TRUE_BB:bb[0-9]+]], [[FALSE_BB:bb[0-9]+]]
// CHECK: [[TRUE_BB]]:
// CHECK: function_ref @$s4Test32unavailableInAlwaysEnabledDomainyyF
// CHECK: [[FALSE_BB]]:
// CHECK: function_ref @$s4Test30availableInAlwaysEnabledDomainyyF
if #unavailable(AlwaysEnabledDomain) {
unavailableInAlwaysEnabledDomain()
} else {
availableInAlwaysEnabledDomain()
}
}
// CHECK: end sil function '$s4Test36testIfUnavailableAlwaysEnabledDomainyyF'
// CHECK-LABEL: sil{{.*}}$s4Test29testIfAvailableDisabledDomainyyF : $@convention(thin) () -> ()
public func testIfAvailableDisabledDomain() {
// CHECK: bb0:

View File

@@ -1,6 +1,7 @@
// RUN: %target-swift-emit-silgen -module-name Test %s -verify \
// RUN: -enable-experimental-feature CustomAvailability \
// RUN: -define-enabled-availability-domain EnabledDomain \
// RUN: -define-always-enabled-availability-domain AlwaysEnabledDomain \
// RUN: -define-disabled-availability-domain DisabledDomain \
// RUN: -define-dynamic-availability-domain DynamicDomain \
// RUN: | %FileCheck %s --check-prefixes=CHECK,CHECK-NOOPT
@@ -8,6 +9,7 @@
// RUN: %target-swift-emit-silgen -module-name Test %s -verify \
// RUN: -enable-experimental-feature CustomAvailability \
// RUN: -define-enabled-availability-domain EnabledDomain \
// RUN: -define-always-enabled-availability-domain AlwaysEnabledDomain \
// RUN: -define-disabled-availability-domain DisabledDomain \
// RUN: -define-dynamic-availability-domain DynamicDomain \
// RUN: -unavailable-decl-optimization=complete \
@@ -26,6 +28,14 @@ public func availableInEnabledDomain() { }
@available(EnabledDomain, unavailable)
public func unavailableInEnabledDomain() { }
// CHECK: s4Test30availableInAlwaysEnabledDomainyyF
@available(AlwaysEnabledDomain)
public func availableInAlwaysEnabledDomain() { }
// CHECK-NOT: s4Test32unavailableInAlwaysEnabledDomainyyF
@available(AlwaysEnabledDomain, unavailable)
public func unavailableInAlwaysEnabledDomain() { }
// CHECK-NOT: s4Test25availableInDisabledDomainyyF
@available(DisabledDomain)
public func availableInDisabledDomain() { }

View File

@@ -1,6 +1,7 @@
// RUN: %target-typecheck-verify-swift \
// RUN: -enable-experimental-feature CustomAvailability \
// RUN: -define-enabled-availability-domain EnabledDomain \
// RUN: -define-always-enabled-availability-domain AlwaysEnabledDomain \
// RUN: -define-enabled-availability-domain RedefinedDomain \
// RUN: -define-disabled-availability-domain DisabledDomain \
// RUN: -define-dynamic-availability-domain DynamicDomain \
@@ -22,6 +23,9 @@ func availableInEnabledDomainWithWildcard() { }
@available(EnabledDomain, introduced: 1.0) // expected-error {{unexpected version number for EnabledDomain}}
func introducedInEnabledDomain() { }
@available(AlwaysEnabledDomain, introduced: 1.0) // expected-error {{unexpected version number for AlwaysEnabledDomain}}
func introducedInAlwaysEnabledDomain() { }
@available(EnabledDomain 1.0) // expected-error {{unexpected version number for EnabledDomain}}
func introducedInEnabledDomainShort() { }
@@ -31,6 +35,9 @@ func introducedInEnabledDomainShortWithWildcard() { }
@available(macOS 10.10, EnabledDomain, *) // expected-error {{EnabledDomain availability must be specified alone}}
func introducedInMacOSAndAvailableInEnabledDomain() { }
@available(macOS 10.10, AlwaysEnabledDomain, *) // expected-error {{AlwaysEnabledDomain availability must be specified alone}}
func introducedInMacOSAndAvailableInAlwaysEnabledDomain() { }
@available(EnabledDomain, macOS 10.10, *) // expected-error {{expected 'available' option such as 'unavailable', 'introduced', 'deprecated', 'obsoleted', 'message', or 'renamed'}}
// expected-error@-1 {{expected declaration}}
func availableInEnabledDomainAndIntroducedInMacOS() { }