Skip to content

Commit e737b23

Browse files
committed
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`.
1 parent a599685 commit e737b23

File tree

7 files changed

+59
-12
lines changed

7 files changed

+59
-12
lines changed

include/swift/AST/DiagnosticGroups.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ GROUP(DeprecatedDeclaration, "DeprecatedDeclaration.md")
2626
GROUP(Unsafe, "Unsafe.md")
2727
GROUP(UnknownWarningGroup, "UnknownWarningGroup.md")
2828
GROUP(PreconcurrencyImport, "PreconcurrencyImport.md")
29+
GROUP(StrictLanguageFeatures, "StrictLanguageFeatures.md")
2930

3031
#define UNDEFINE_DIAGNOSTIC_GROUPS_MACROS
3132
#include "swift/AST/DefineDiagnosticGroupsMacros.h"

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,18 @@ ERROR(error_unsupported_target_arch, none,
3737
"unsupported target architecture: '%0'", (StringRef))
3838

3939
WARNING(warning_upcoming_feature_on_by_default, none,
40-
"upcoming feature '%0' is already enabled as of Swift version %1",
41-
(StringRef, unsigned))
40+
"upcoming feature '%0' is already enabled as of Swift version %1",
41+
(StringRef, unsigned))
42+
43+
GROUPED_WARNING(unrecognized_feature, StrictLanguageFeatures, DefaultIgnore,
44+
"'%0' is not a recognized "
45+
"%select{experimental|upcoming}1 feature",
46+
(StringRef, bool))
47+
48+
GROUPED_WARNING(feature_not_experimental, StrictLanguageFeatures, DefaultIgnore,
49+
"'%0' is not an experimental feature, "
50+
"use -%select{disable|enable}1-upcoming-feature instead",
51+
(StringRef, bool))
4252

4353
ERROR(error_unknown_library_level, none,
4454
"unknown library level '%0', "

lib/Frontend/CompilerInvocation.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,8 @@ static bool ParseEnabledFeatureArgs(LangOptions &Opts, ArgList &Args,
758758
auto &option = A->getOption();
759759
StringRef value = A->getValue();
760760
bool enableUpcoming = option.matches(OPT_enable_upcoming_feature);
761+
bool isUpcomingFlag =
762+
enableUpcoming || option.matches(OPT_disable_upcoming_feature);
761763
bool enableFeature =
762764
enableUpcoming || option.matches(OPT_enable_experimental_feature);
763765

@@ -770,20 +772,28 @@ static bool ParseEnabledFeatureArgs(LangOptions &Opts, ArgList &Args,
770772
continue;
771773
}
772774

773-
// If this was specified as an "upcoming feature", it must be recognized
774-
// as one.
775775
auto feature = getUpcomingFeature(value);
776-
if (enableUpcoming || option.matches(OPT_disable_upcoming_feature)) {
777-
if (!feature)
776+
if (feature) {
777+
// Diagnose upcoming features enabled with -enable-experimental-feature.
778+
if (!isUpcomingFlag)
779+
Diags.diagnose(SourceLoc(), diag::feature_not_experimental, value,
780+
enableFeature);
781+
} else {
782+
// If -enable-upcoming-feature was used and an upcoming feature was not
783+
// found, diagnose and continue.
784+
if (isUpcomingFlag) {
785+
Diags.diagnose(SourceLoc(), diag::unrecognized_feature, value,
786+
/*upcoming=*/true);
778787
continue;
779-
}
788+
}
780789

781-
// If it's not recognized as either an upcoming feature or an experimental
782-
// feature, skip it.
783-
if (!feature) {
790+
// If the feature is no a recognized experimental feature either, skip it.
784791
feature = getExperimentalFeature(value);
785-
if (!feature)
792+
if (!feature) {
793+
Diags.diagnose(SourceLoc(), diag::unrecognized_feature, value,
794+
/*upcoming=*/false);
786795
continue;
796+
}
787797
}
788798

789799
// Skip features that are already enabled or disabled.

test/Frontend/strict_features.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %target-swift-frontend -typecheck -enable-upcoming-feature UnknownFeature %s 2>&1 | %FileCheck %s --check-prefix=CHECK-NO-DIAGS --allow-empty
2+
3+
// With -Wwarning StrictLanguageFeatures, emit extra diagnostics for
4+
// misspecified features.
5+
// RUN: %target-swift-frontend -typecheck -Wwarning StrictLanguageFeatures -enable-upcoming-feature UnknownFeature %s 2>&1 | %FileCheck %s --check-prefix=CHECK-UNKNOWN-UPCOMING
6+
// RUN: %target-swift-frontend -typecheck -Wwarning StrictLanguageFeatures -enable-experimental-feature UnknownFeature %s 2>&1 | %FileCheck %s --check-prefix=CHECK-UNKNOWN-EXPERIMENTAL
7+
// 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
8+
// 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
9+
10+
// REQUIRES: swift_feature_ConciseMagicFile
11+
12+
// CHECK-NO-DIAGS-NOT: warning:
13+
// CHECK-NO-DIAGS-NOT: error:
14+
15+
// CHECK-UNKNOWN-UPCOMING: warning: 'UnknownFeature' is not a recognized upcoming feature
16+
// CHECK-UNKNOWN-EXPERIMENTAL: warning: 'UnknownFeature' is not a recognized experimental feature
17+
// CHECK-NOT-EXPERIMENTAL-ENABLE: warning: 'ConciseMagicFile' is not an experimental feature, use -enable-upcoming-feature instead
18+
// CHECK-NOT-EXPERIMENTAL-DISABLE: warning: 'ConciseMagicFile' is not an experimental feature, use -disable-upcoming-feature instead

test/Frontend/upcoming_feature.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
// RUN: %target-swift-frontend -typecheck -disable-experimental-feature ConciseMagicFile -swift-version 6 %s 2>&1 | %FileCheck %s
3838

3939
// REQUIRES: swift_feature_ConciseMagicFile
40-
// REQUIRES: !swift_feature_UnknownFeature
4140

4241
// CHECK: warning: upcoming feature 'ConciseMagicFile' is already enabled as of Swift version 6
4342

test/Misc/verify-swift-feature-testing.test-sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ EXCEPTIONAL_FILES = [
1616
pathlib.Path("test/Frontend/experimental-features-no-asserts.swift"),
1717
# Tests for UnknownFeature not existing
1818
pathlib.Path("test/Frontend/upcoming_feature.swift"),
19+
pathlib.Path("test/Frontend/strict_features.swift"),
1920
# Tests for ModuleInterfaceExportAs being ignored
2021
pathlib.Path("test/ModuleInterface/swift-export-as.swift"),
2122
# Uses the pseudo-feature AvailabilityMacro=
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Strict language feature enablement
2+
3+
By default, if an unrecognized feature name is specified with the
4+
`-enable-upcoming-feature` or `-enable-experimental-feature` flags, the compiler
5+
will ignore it without emitting a diagnostic since some projects must be
6+
simultaneously compatible with multiple versions of the language and toolchain.
7+
However, this warning group can be enabled to opt-in to detailed diagnostics
8+
about misspecified features.

0 commit comments

Comments
 (0)