AST: Diagnose unrecognized platforms as errors with CustomAvailability enabled.

When the CustomAvailability experimental feature is enabled, make it an error
to specify an unrecognized availability domain name. Also, add these
diagnostics to a diagnostic group so that developers can control their behavior
when they are warnings.

Resolves rdar://152741624.
This commit is contained in:
Allan Shortlidge
2025-06-06 17:22:55 -07:00
parent 4051ea2e78
commit f5bae411ca
9 changed files with 42 additions and 15 deletions

View File

@@ -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")

View File

@@ -6836,11 +6836,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))

View File

@@ -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);

View File

@@ -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)

View File

@@ -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() {

View File

@@ -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}}

View File

@@ -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() {

View File

@@ -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() { }

View File

@@ -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.