diff --git a/include/swift/AST/DiagnosticGroups.def b/include/swift/AST/DiagnosticGroups.def index f5eab826de0f8..dd1e8a8cd3390 100644 --- a/include/swift/AST/DiagnosticGroups.def +++ b/include/swift/AST/DiagnosticGroups.def @@ -41,6 +41,7 @@ GROUP(no_group, "") GROUP(ActorIsolatedCall, "actor-isolated-call") +GROUP(AvailabilityUnrecognizedName, "availability-unrecognized-name") GROUP(ClangDeclarationImport, "clang-declaration-import") GROUP(ConformanceIsolation, "conformance-isolation") GROUP(DeprecatedDeclaration, "deprecated-declaration") diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index f79d13ab8af2a..3541aed714058 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -6913,11 +6913,12 @@ ERROR(availability_must_occur_alone, none, (AvailabilityDomain, bool)) ERROR(availability_unexpected_version, none, "unexpected version number for %0", (AvailabilityDomain)) -WARNING(availability_unrecognized_platform_name, - PointsToFirstBadToken, "unrecognized platform name %0", (Identifier)) -WARNING(availability_suggest_platform_name, - PointsToFirstBadToken, "unrecognized platform name %0;" - " did you mean '%1'?", +GROUPED_ERROR(availability_unrecognized_platform_name, + AvailabilityUnrecognizedName, PointsToFirstBadToken, + "unrecognized platform name %0", (Identifier)) +GROUPED_ERROR(availability_suggest_platform_name, + AvailabilityUnrecognizedName, PointsToFirstBadToken, + "unrecognized platform name %0; did you mean '%1'?", (Identifier, StringRef)) WARNING(availability_unsupported_version_number, none, "'%0' is not a supported version number", (llvm::VersionTuple)) diff --git a/lib/AST/AvailabilityDomain.cpp b/lib/AST/AvailabilityDomain.cpp index 96e5d48d07cdd..bc2e0a2fa9272 100644 --- a/lib/AST/AvailabilityDomain.cpp +++ b/lib/AST/AvailabilityDomain.cpp @@ -368,22 +368,29 @@ AvailabilityDomainOrIdentifier::lookUpInDeclContext( domain = results.front(); } + bool hasCustomAvailability = + ctx.LangOpts.hasFeature(Feature::CustomAvailability); + if (!domain) { auto domainString = identifier.str(); + bool downgradeErrors = + !hasCustomAvailability || declContext->isInSwiftinterface(); if (auto suggestion = closestCorrectedPlatformString(domainString)) { diags .diagnose(loc, diag::availability_suggest_platform_name, identifier, *suggestion) + .limitBehaviorIf(downgradeErrors, DiagnosticBehavior::Warning) .fixItReplace(SourceRange(loc), *suggestion); } else { - diags.diagnose(loc, diag::availability_unrecognized_platform_name, - identifier); + diags + .diagnose(loc, diag::availability_unrecognized_platform_name, + identifier) + .limitBehaviorIf(downgradeErrors, DiagnosticBehavior::Warning); } return std::nullopt; } - if (domain->isCustom() && - !ctx.LangOpts.hasFeature(Feature::CustomAvailability) && + if (domain->isCustom() && !hasCustomAvailability && !declContext->isInSwiftinterface()) { diags.diagnose(loc, diag::attr_availability_requires_custom_availability, *domain); diff --git a/test/ClangImporter/Inputs/availability_custom_domains_other.swift b/test/ClangImporter/Inputs/availability_custom_domains_other.swift index f51a436531000..43477f09c8185 100644 --- a/test/ClangImporter/Inputs/availability_custom_domains_other.swift +++ b/test/ClangImporter/Inputs/availability_custom_domains_other.swift @@ -1,6 +1,6 @@ import Seas -@available(Arctic) // expected-warning {{unrecognized platform name 'Arctic'}} +@available(Arctic) // expected-error {{unrecognized platform name 'Arctic'}} func availableInArctic() { } @available(Mediterranean) diff --git a/test/ClangImporter/availability_custom_domains.swift b/test/ClangImporter/availability_custom_domains.swift index 0a87fae61bddb..ca81219d69645 100644 --- a/test/ClangImporter/availability_custom_domains.swift +++ b/test/ClangImporter/availability_custom_domains.swift @@ -44,7 +44,7 @@ func availableInPacific() { } func unavailableInColorado() { } // expected-note {{'unavailableInColorado()' has been explicitly marked unavailable here}} // The Seas module is only imported directly by the other source file. -@available(Baltic) // expected-warning {{unrecognized platform name 'Baltic'}} +@available(Baltic) // expected-error {{unrecognized platform name 'Baltic'}} func availableInBaltic() { } // expected-note {{did you mean 'availableInBaltic'}} func testSwiftDecls() { diff --git a/test/Parse/availability_query_custom_domains.swift b/test/Parse/availability_query_custom_domains.swift index 1b176b437bc42..e556a17151bc9 100644 --- a/test/Parse/availability_query_custom_domains.swift +++ b/test/Parse/availability_query_custom_domains.swift @@ -9,13 +9,13 @@ if #available(EnabledDomain) { } if #available(DisabledDomain) { } if #available(DynamicDomain) { } -if #available(UnknownDomain) { } // expected-warning {{unrecognized platform name 'UnknownDomain'}} +if #available(UnknownDomain) { } // expected-error {{unrecognized platform name 'UnknownDomain'}} // expected-error@-1 {{condition required for target platform}} if #unavailable(EnabledDomain) { } if #unavailable(DisabledDomain) { } if #unavailable(DynamicDomain) { } -if #unavailable(UnknownDomain) { } // expected-warning {{unrecognized platform name 'UnknownDomain'}} +if #unavailable(UnknownDomain) { } // expected-error {{unrecognized platform name 'UnknownDomain'}} if #available(EnabledDomain 1.0) { } // expected-error {{unexpected version number for EnabledDomain}} if #available(EnabledDomain, DisabledDomain) { } // expected-error {{EnabledDomain availability must be specified alone}} diff --git a/test/Sema/availability_custom_domains.swift b/test/Sema/availability_custom_domains.swift index 4caac2ec87824..39a18d0408eab 100644 --- a/test/Sema/availability_custom_domains.swift +++ b/test/Sema/availability_custom_domains.swift @@ -26,7 +26,7 @@ func deprecatedInDynamicDomain() { } @available(DynamicDomain, unavailable) func unavailableInDynamicDomain() { } // expected-note * {{'unavailableInDynamicDomain()' has been explicitly marked unavailable here}} -@available(UnknownDomain) // expected-warning {{unrecognized platform name 'UnknownDomain'}} +@available(UnknownDomain) // expected-error {{unrecognized platform name 'UnknownDomain'}} func availableInUnknownDomain() { } func testDeployment() { diff --git a/test/attr/attr_availability_custom_domains.swift b/test/attr/attr_availability_custom_domains.swift index 4dba8063eec3e..14d0f3f62d897 100644 --- a/test/attr/attr_availability_custom_domains.swift +++ b/test/attr/attr_availability_custom_domains.swift @@ -57,5 +57,5 @@ func deprecatedInRedefinedDomain() { } @available(DynamicDomain) func availableInDynamicDomain() { } -@available(UnknownDomain) // expected-warning {{unrecognized platform name 'UnknownDomain'}} +@available(UnknownDomain) // expected-error {{unrecognized platform name 'UnknownDomain'}} func availableInUnknownDomain() { } diff --git a/userdocs/diagnostics/availability-unrecognized-name.md b/userdocs/diagnostics/availability-unrecognized-name.md new file mode 100644 index 0000000000000..1caf5bb107c11 --- /dev/null +++ b/userdocs/diagnostics/availability-unrecognized-name.md @@ -0,0 +1,18 @@ +# Unrecognized availability platforms (AvailabilityUnrecognizedName) + +Warnings that identify unrecognized platform names in `@available` attributes and `if #available` statements. + +## Overview + +The `AvailabilityUnrecognizedName` group covers warnings emitted when the platform name specified in an availability related construct is unrecognized by the compiler: + +``` +@available(NotAValidPlatform, introduced: 1.0) // warning: unrecognized platform name 'NotAValidPlatform' +public func function() { + if #available(NotAValidPlatform 2.0, *) { // warning: unrecognized platform name 'NotAValidPlatform' + // ... + } +} +``` + +Availability specifications with unrecognized platform names in `@available` attributes and `#available` queries are ignored by the compiler.