mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Frontend: Implement optional parsing diagnostics for enabled language features.
Parsing for `-enable-upcoming-feature` and `-enable-experimental-feature` is lenient by default because some projects need to be compatible with multiple language versions and compiler toolchains simultaneously, and strict diagnostics would be a nuisance. On the other hand, though, it would be useful to get feedback from the compiler when you attempt to enable a feature that doesn't exist. This change splits the difference by introducing new diagnostics for potential feature enablement misconfigurations but leaves those diagnostics ignored by default. Projects that wish to use them can specify `-Wwarning StrictLanguageFeatures`.
This commit is contained in:
@@ -26,6 +26,7 @@ GROUP(DeprecatedDeclaration, "DeprecatedDeclaration.md")
|
||||
GROUP(Unsafe, "Unsafe.md")
|
||||
GROUP(UnknownWarningGroup, "UnknownWarningGroup.md")
|
||||
GROUP(PreconcurrencyImport, "PreconcurrencyImport.md")
|
||||
GROUP(StrictLanguageFeatures, "StrictLanguageFeatures.md")
|
||||
|
||||
#define UNDEFINE_DIAGNOSTIC_GROUPS_MACROS
|
||||
#include "swift/AST/DefineDiagnosticGroupsMacros.h"
|
||||
|
||||
@@ -37,8 +37,18 @@ ERROR(error_unsupported_target_arch, none,
|
||||
"unsupported target architecture: '%0'", (StringRef))
|
||||
|
||||
WARNING(warning_upcoming_feature_on_by_default, none,
|
||||
"upcoming feature '%0' is already enabled as of Swift version %1",
|
||||
(StringRef, unsigned))
|
||||
"upcoming feature '%0' is already enabled as of Swift version %1",
|
||||
(StringRef, unsigned))
|
||||
|
||||
GROUPED_WARNING(unrecognized_feature, StrictLanguageFeatures, DefaultIgnore,
|
||||
"'%0' is not a recognized "
|
||||
"%select{experimental|upcoming}1 feature",
|
||||
(StringRef, bool))
|
||||
|
||||
GROUPED_WARNING(feature_not_experimental, StrictLanguageFeatures, DefaultIgnore,
|
||||
"'%0' is not an experimental feature, "
|
||||
"use -%select{disable|enable}1-upcoming-feature instead",
|
||||
(StringRef, bool))
|
||||
|
||||
ERROR(error_unknown_library_level, none,
|
||||
"unknown library level '%0', "
|
||||
|
||||
@@ -745,6 +745,8 @@ static bool ParseEnabledFeatureArgs(LangOptions &Opts, ArgList &Args,
|
||||
auto &option = A->getOption();
|
||||
StringRef value = A->getValue();
|
||||
bool enableUpcoming = option.matches(OPT_enable_upcoming_feature);
|
||||
bool isUpcomingFlag =
|
||||
enableUpcoming || option.matches(OPT_disable_upcoming_feature);
|
||||
bool enableFeature =
|
||||
enableUpcoming || option.matches(OPT_enable_experimental_feature);
|
||||
|
||||
@@ -757,20 +759,28 @@ static bool ParseEnabledFeatureArgs(LangOptions &Opts, ArgList &Args,
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this was specified as an "upcoming feature", it must be recognized
|
||||
// as one.
|
||||
auto feature = getUpcomingFeature(value);
|
||||
if (enableUpcoming || option.matches(OPT_disable_upcoming_feature)) {
|
||||
if (!feature)
|
||||
if (feature) {
|
||||
// Diagnose upcoming features enabled with -enable-experimental-feature.
|
||||
if (!isUpcomingFlag)
|
||||
Diags.diagnose(SourceLoc(), diag::feature_not_experimental, value,
|
||||
enableFeature);
|
||||
} else {
|
||||
// If -enable-upcoming-feature was used and an upcoming feature was not
|
||||
// found, diagnose and continue.
|
||||
if (isUpcomingFlag) {
|
||||
Diags.diagnose(SourceLoc(), diag::unrecognized_feature, value,
|
||||
/*upcoming=*/true);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If it's not recognized as either an upcoming feature or an experimental
|
||||
// feature, skip it.
|
||||
if (!feature) {
|
||||
// If the feature is also not a recognized experimental feature, skip it.
|
||||
feature = getExperimentalFeature(value);
|
||||
if (!feature)
|
||||
if (!feature) {
|
||||
Diags.diagnose(SourceLoc(), diag::unrecognized_feature, value,
|
||||
/*upcoming=*/false);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip features that are already enabled or disabled.
|
||||
|
||||
18
test/Frontend/strict_features.swift
Normal file
18
test/Frontend/strict_features.swift
Normal file
@@ -0,0 +1,18 @@
|
||||
// RUN: %target-swift-frontend -typecheck -enable-upcoming-feature UnknownFeature %s 2>&1 | %FileCheck %s --check-prefix=CHECK-NO-DIAGS --allow-empty
|
||||
|
||||
// With -Wwarning StrictLanguageFeatures, emit extra diagnostics for
|
||||
// misspecified features.
|
||||
// RUN: %target-swift-frontend -typecheck -Wwarning StrictLanguageFeatures -enable-upcoming-feature UnknownFeature %s 2>&1 | %FileCheck %s --check-prefix=CHECK-UNKNOWN-UPCOMING
|
||||
// RUN: %target-swift-frontend -typecheck -Wwarning StrictLanguageFeatures -enable-experimental-feature UnknownFeature %s 2>&1 | %FileCheck %s --check-prefix=CHECK-UNKNOWN-EXPERIMENTAL
|
||||
// RUN: %target-swift-frontend -typecheck -Wwarning StrictLanguageFeatures -swift-version 5 -enable-experimental-feature ConciseMagicFile %s 2>&1 | %FileCheck %s --check-prefix=CHECK-NOT-EXPERIMENTAL-ENABLE
|
||||
// RUN: %target-swift-frontend -typecheck -Wwarning StrictLanguageFeatures -swift-version 5 -enable-experimental-feature ConciseMagicFile -disable-experimental-feature ConciseMagicFile %s 2>&1 | %FileCheck %s --check-prefix=CHECK-NOT-EXPERIMENTAL-DISABLE
|
||||
|
||||
// REQUIRES: swift_feature_ConciseMagicFile
|
||||
|
||||
// CHECK-NO-DIAGS-NOT: warning:
|
||||
// CHECK-NO-DIAGS-NOT: error:
|
||||
|
||||
// CHECK-UNKNOWN-UPCOMING: warning: 'UnknownFeature' is not a recognized upcoming feature
|
||||
// CHECK-UNKNOWN-EXPERIMENTAL: warning: 'UnknownFeature' is not a recognized experimental feature
|
||||
// CHECK-NOT-EXPERIMENTAL-ENABLE: warning: 'ConciseMagicFile' is not an experimental feature, use -enable-upcoming-feature instead
|
||||
// CHECK-NOT-EXPERIMENTAL-DISABLE: warning: 'ConciseMagicFile' is not an experimental feature, use -disable-upcoming-feature instead
|
||||
@@ -37,7 +37,6 @@
|
||||
// RUN: %target-swift-frontend -typecheck -disable-experimental-feature ConciseMagicFile -swift-version 6 %s 2>&1 | %FileCheck %s
|
||||
|
||||
// REQUIRES: swift_feature_ConciseMagicFile
|
||||
// REQUIRES: !swift_feature_UnknownFeature
|
||||
|
||||
// CHECK: warning: upcoming feature 'ConciseMagicFile' is already enabled as of Swift version 6
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ EXCEPTIONAL_FILES = [
|
||||
pathlib.Path("test/Frontend/experimental-features-no-asserts.swift"),
|
||||
# Tests for UnknownFeature not existing
|
||||
pathlib.Path("test/Frontend/upcoming_feature.swift"),
|
||||
pathlib.Path("test/Frontend/strict_features.swift"),
|
||||
# Tests for ModuleInterfaceExportAs being ignored
|
||||
pathlib.Path("test/ModuleInterface/swift-export-as.swift"),
|
||||
# Uses the pseudo-feature AvailabilityMacro=
|
||||
|
||||
8
userdocs/diagnostic_groups/StrictLanguageFeatures.md
Normal file
8
userdocs/diagnostic_groups/StrictLanguageFeatures.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# Strict language feature enablement
|
||||
|
||||
By default, if an unrecognized feature name is specified with the
|
||||
`-enable-upcoming-feature` or `-enable-experimental-feature` flags, the compiler
|
||||
will ignore it without emitting a diagnostic since some projects must be
|
||||
simultaneously compatible with multiple versions of the language and toolchain.
|
||||
However, this warning group can be enabled to opt-in to detailed diagnostics
|
||||
about misspecified features.
|
||||
Reference in New Issue
Block a user