Skip to content

Commit ea5a645

Browse files
authored
Merge pull request #66992 from DougGregor/experimental-feature-strict-concurrency-5.9
2 parents 0bc89b6 + f088830 commit ea5a645

File tree

5 files changed

+83
-1
lines changed

5 files changed

+83
-1
lines changed

include/swift/Basic/Features.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,9 @@ EXPERIMENTAL_FEATURE(ReferenceBindings, false)
203203
/// Enable the explicit 'import Builtin' and allow Builtin usage.
204204
EXPERIMENTAL_FEATURE(BuiltinModule, true)
205205

206+
// Enable strict concurrency.
207+
EXPERIMENTAL_FEATURE(StrictConcurrency, true)
208+
206209
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
207210
#undef EXPERIMENTAL_FEATURE
208211
#undef UPCOMING_FEATURE

lib/AST/ASTPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3174,6 +3174,10 @@ static bool usesFeatureExistentialAny(Decl *decl) {
31743174
return false;
31753175
}
31763176

3177+
static bool usesFeatureStrictConcurrency(Decl *decl) {
3178+
return false;
3179+
}
3180+
31773181
static bool usesFeatureImportObjcForwardDeclarations(Decl *decl) {
31783182
ClangNode clangNode = decl->getClangNode();
31793183
if (!clangNode)

lib/Frontend/CompilerInvocation.cpp

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,15 @@ static void diagnoseCxxInteropCompatMode(Arg *verArg, ArgList &Args,
508508
diags.diagnose(SourceLoc(), diag::valid_cxx_interop_modes, versStr);
509509
}
510510

511+
static llvm::Optional<StrictConcurrency>
512+
parseStrictConcurrency(StringRef value) {
513+
return llvm::StringSwitch<llvm::Optional<StrictConcurrency>>(value)
514+
.Case("minimal", StrictConcurrency::Minimal)
515+
.Case("targeted", StrictConcurrency::Targeted)
516+
.Case("complete", StrictConcurrency::Complete)
517+
.Default(llvm::None);
518+
}
519+
511520
static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
512521
DiagnosticEngine &Diags,
513522
const FrontendOptions &FrontendOpts) {
@@ -753,9 +762,33 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
753762
addFutureFeatureIfNotImplied(Feature::BareSlashRegexLiterals);
754763

755764
for (const Arg *A : Args.filtered(OPT_enable_experimental_feature)) {
765+
// Allow StrictConcurrency to have a value that corresponds to the
766+
// -strict-concurrency=<blah> settings.
767+
StringRef value = A->getValue();
768+
if (value.startswith("StrictConcurrency")) {
769+
auto decomposed = value.split("=");
770+
if (decomposed.first == "StrictConcurrency") {
771+
bool handled;
772+
if (decomposed.second == "") {
773+
Opts.StrictConcurrencyLevel = StrictConcurrency::Complete;
774+
handled = true;
775+
} else if (auto level = parseStrictConcurrency(decomposed.second)) {
776+
Opts.StrictConcurrencyLevel = *level;
777+
handled = true;
778+
} else {
779+
handled = false;
780+
}
781+
782+
if (handled) {
783+
Opts.Features.insert(Feature::StrictConcurrency);
784+
continue;
785+
}
786+
}
787+
}
788+
756789
// If this is a known experimental feature, allow it in +Asserts
757790
// (non-release) builds for testing purposes.
758-
if (auto feature = getExperimentalFeature(A->getValue())) {
791+
if (auto feature = getExperimentalFeature(value)) {
759792
#ifdef NDEBUG
760793
if (!isFeatureAvailableInProduction(*feature)) {
761794
Diags.diagnose(SourceLoc(),
@@ -913,6 +946,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
913946

914947
} else if (Args.hasArg(OPT_warn_concurrency)) {
915948
Opts.StrictConcurrencyLevel = StrictConcurrency::Complete;
949+
} else if (Opts.hasFeature(Feature::StrictConcurrency)) {
950+
// Already set above.
916951
} else {
917952
// Default to minimal checking in Swift 5.x.
918953
Opts.StrictConcurrencyLevel = StrictConcurrency::Minimal;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-feature StrictConcurrency
2+
// RUN: %target-typecheck-verify-swift -enable-experimental-feature StrictConcurrency=complete
3+
// REQUIRES: concurrency
4+
5+
class C1 { } // expected-note{{class 'C1' does not conform to the 'Sendable' protocol}}
6+
class C2 { }
7+
8+
@available(*, unavailable)
9+
extension C2: Sendable {} // expected-note{{conformance of 'C2' to 'Sendable' has been explicitly marked unavailable here}}
10+
11+
protocol TestProtocol {
12+
associatedtype Value: Sendable
13+
}
14+
15+
struct Test1: TestProtocol { // expected-warning{{type 'Test1.Value' (aka 'C1') does not conform to the 'Sendable' protocol}}
16+
typealias Value = C1
17+
}
18+
19+
struct Test2: TestProtocol { // expected-warning{{conformance of 'C2' to 'Sendable' is unavailable}}
20+
// expected-note@-1{{in associated type 'Self.Value' (inferred as 'C2')}}
21+
typealias Value = C2
22+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-feature StrictConcurrency=targeted
2+
// REQUIRES: concurrency
3+
4+
class C { // expected-note{{class 'C' does not conform to the 'Sendable' protocol}}
5+
var counter = 0
6+
}
7+
8+
func acceptsSendable<T: Sendable>(_: T) { }
9+
10+
func testNoConcurrency(c: C) {
11+
acceptsSendable(c)
12+
}
13+
14+
@available(SwiftStdlib 5.1, *)
15+
func testConcurrency(c: C) async {
16+
acceptsSendable(c) // expected-warning{{type 'C' does not conform to the 'Sendable' protocol}}
17+
}
18+

0 commit comments

Comments
 (0)