diff --git a/include/swift/AST/AvailabilityDomain.h b/include/swift/AST/AvailabilityDomain.h index cc5b6e1941502..86001ffb4b39b 100644 --- a/include/swift/AST/AvailabilityDomain.h +++ b/include/swift/AST/AvailabilityDomain.h @@ -226,11 +226,12 @@ class AvailabilityDomain final { /// 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 @@ class CustomAvailabilityDomain : public llvm::FoldingSetNode { 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. diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index a120e58903263..2400309f9eff8 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -615,6 +615,8 @@ class FrontendOptions { struct CustomAvailabilityDomains { /// Domains defined with `-define-enabled-availability-domain=`. llvm::SmallVector EnabledDomains; + /// Domains defined with `-define-always-enabled-availability-domain=`. + llvm::SmallVector AlwaysEnabledDomains; /// Domains defined with `-define-disabled-availability-domain=`. llvm::SmallVector DisabledDomains; /// Domains defined with `-define-dynamic-availability-domain=`. diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index 659a531e1b988..b3f027bf265fc 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -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<"">; +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<"">; + 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">, diff --git a/lib/AST/AvailabilityConstraint.cpp b/lib/AST/AvailabilityConstraint.cpp index 0eb542a339d2e..22a56f6fba68e 100644 --- a/lib/AST/AvailabilityConstraint.cpp +++ b/lib/AST/AvailabilityConstraint.cpp @@ -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 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 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 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); } } diff --git a/lib/AST/AvailabilityDomain.cpp b/lib/AST/AvailabilityDomain.cpp index 8a3a073eaf873..774b69b1242d0 100644 --- a/lib/AST/AvailabilityDomain.cpp +++ b/lib/AST/AvailabilityDomain.cpp @@ -33,6 +33,8 @@ getCustomDomainKind(clang::FeatureAvailKind featureAvailKind) { return CustomAvailabilityDomain::Kind::Disabled; case clang::FeatureAvailKind::Dynamic: return CustomAvailabilityDomain::Kind::Dynamic; + case clang::FeatureAvailKind::AlwaysAvailable: + return CustomAvailabilityDomain::Kind::AlwaysEnabled; default: llvm::report_fatal_error("unexpected kind"); } @@ -57,6 +59,7 @@ customDomainForClangDecl(ValueDecl *decl) { case clang::FeatureAvailKind::Available: case clang::FeatureAvailKind::Unavailable: case clang::FeatureAvailKind::Dynamic: + case clang::FeatureAvailKind::AlwaysAvailable: break; default: return nullptr; @@ -181,7 +184,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 +193,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 +201,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 @@ -224,8 +229,23 @@ getDeploymentVersion(const AvailabilityDomain &domain, const ASTContext &ctx) { std::optional 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; } diff --git a/lib/AST/AvailabilityScopeBuilder.cpp b/lib/AST/AvailabilityScopeBuilder.cpp index 0231cf16b50cf..7d6fdc68b3dd5 100644 --- a/lib/AST/AvailabilityScopeBuilder.cpp +++ b/lib/AST/AvailabilityScopeBuilder.cpp @@ -881,6 +881,7 @@ class AvailabilityScopeBuilder : private ASTWalker { 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); diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index ee8a94f3a0beb..79dc8da457bd8 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -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)) diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 682b50623ab15..f6d287241c281 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -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) diff --git a/test/Availability/availability_custom_domains.swift b/test/Availability/availability_custom_domains.swift index d1ff7c1fd3609..a30f5e38aadf3 100644 --- a/test/Availability/availability_custom_domains.swift +++ b/test/Availability/availability_custom_domains.swift @@ -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}} diff --git a/test/ClangImporter/Inputs/availability_custom_domains_other.swift b/test/ClangImporter/Inputs/availability_custom_domains_other.swift index 73f6f438ecfc4..b4ff807e01264 100644 --- a/test/ClangImporter/Inputs/availability_custom_domains_other.swift +++ b/test/ClangImporter/Inputs/availability_custom_domains_other.swift @@ -9,4 +9,26 @@ func availableInMediterranean() { } func testOtherClangDecls() { // expected-note {{add '@available' attribute to enclosing global function}} available_in_baltic() // expected-error {{'available_in_baltic()' is only available in Baltic}} // expected-note@-1 {{add 'if #available' version check}} + available_in_bering() // ok, Bering is always available + unavailable_in_bering() // expected-error {{'unavailable_in_bering()' is unavailable}} +} + +@available(Baltic) +func availableInBalticOther() { + available_in_baltic() + available_in_bering() // ok, Bering is always available + unavailable_in_bering() // expected-error {{'unavailable_in_bering()' is unavailable}} +} + +@available(Bering) +func availableInBering() { // expected-note {{add '@available' attribute to enclosing global function}} + available_in_baltic() // expected-error {{'available_in_baltic()' is only available in Baltic}} + // expected-note@-1 {{add 'if #available' version check}} + available_in_bering() + unavailable_in_bering() // expected-error {{'unavailable_in_bering()' is unavailable}} +} + +@available(Bering, unavailable) +func unavailableInBering() { + unavailable_in_bering() } diff --git a/test/IRGen/availability_custom_domains.swift b/test/IRGen/availability_custom_domains.swift index 7545fdddbb972..33b6fbbf08a24 100644 --- a/test/IRGen/availability_custom_domains.swift +++ b/test/IRGen/availability_custom_domains.swift @@ -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() diff --git a/test/Inputs/custom-modules/availability-domains/Seas.h b/test/Inputs/custom-modules/availability-domains/Seas.h index e867f995a7e8e..d67cb296ed25b 100644 --- a/test/Inputs/custom-modules/availability-domains/Seas.h +++ b/test/Inputs/custom-modules/availability-domains/Seas.h @@ -3,6 +3,7 @@ int aegean_pred(void); CLANG_ENABLED_AVAILABILITY_DOMAIN(Baltic); +CLANG_ALWAYS_ENABLED_AVAILABILITY_DOMAIN(Bering); CLANG_DISABLED_AVAILABILITY_DOMAIN(Mediterranean); CLANG_DYNAMIC_AVAILABILITY_DOMAIN(Aegean, aegean_pred); @@ -12,5 +13,11 @@ CLANG_DYNAMIC_AVAILABILITY_DOMAIN(Aegean, aegean_pred); __attribute__((availability(domain:Baltic, AVAIL))) void available_in_baltic(void); +__attribute__((availability(domain:Bering, AVAIL))) +void available_in_bering(void); + +__attribute__((availability(domain:Bering, UNAVAIL))) +void unavailable_in_bering(void); + #undef UNAVAIL #undef AVAIL diff --git a/test/SILGen/availability_query_custom_domains.swift b/test/SILGen/availability_query_custom_domains.swift index 52384e6508964..6aeddd68043cf 100644 --- a/test/SILGen/availability_query_custom_domains.swift +++ b/test/SILGen/availability_query_custom_domains.swift @@ -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: diff --git a/test/SILGen/unavailable_decl_custom_domain.swift b/test/SILGen/unavailable_decl_custom_domain.swift index 08462dd11d4fd..abf1572e378b2 100644 --- a/test/SILGen/unavailable_decl_custom_domain.swift +++ b/test/SILGen/unavailable_decl_custom_domain.swift @@ -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() { } diff --git a/test/attr/attr_availability_custom_domains.swift b/test/attr/attr_availability_custom_domains.swift index 150b7abfd2cf6..5e0ff387a64f7 100644 --- a/test/attr/attr_availability_custom_domains.swift +++ b/test/attr/attr_availability_custom_domains.swift @@ -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() { }