Skip to content

Commit 2d4198f

Browse files
authored
Merge pull request swiftlang#36318 from DougGregor/warn-concurrency
2 parents 09e1c34 + 6efaf7a commit 2d4198f

File tree

13 files changed

+51
-20
lines changed

13 files changed

+51
-20
lines changed

include/swift/Basic/LangOptions.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,12 @@ namespace swift {
238238
/// optimized custom allocator, so that memory debugging tools can be used.
239239
bool UseMalloc = false;
240240

241+
/// Provide additional warnings about code that is unsafe in the
242+
/// eventual Swift concurrency model, and will eventually become errors
243+
/// in a future Swift language version, but are too noisy for existing
244+
/// language modes.
245+
bool WarnConcurrency = false;
246+
241247
/// Enable experimental #assert feature.
242248
bool EnableExperimentalStaticAssert = false;
243249

include/swift/Option/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,11 @@ def warn_swift3_objc_inference : Flag<["-"], "warn-swift3-objc-inference">,
616616
Alias<warn_swift3_objc_inference_complete>,
617617
Flags<[FrontendOption, DoesNotAffectIncrementalBuild, HelpHidden]>;
618618

619+
def warn_concurrency : Flag<["-"], "warn-concurrency">,
620+
Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>,
621+
HelpText<"Warn about code that is unsafe according to the Swift Concurrency "
622+
"model and will become ill-formed in a future language version">;
623+
619624
def Rpass_EQ : Joined<["-"], "Rpass=">,
620625
Flags<[FrontendOption]>,
621626
HelpText<"Report performed transformations by optimization passes whose "

lib/Driver/ToolChains.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
217217
inputArgs.AddLastArg(arguments,
218218
options::OPT_warn_swift3_objc_inference_minimal,
219219
options::OPT_warn_swift3_objc_inference_complete);
220+
inputArgs.AddLastArg(arguments, options::OPT_warn_concurrency);
220221
inputArgs.AddLastArg(arguments, options::OPT_warn_implicit_overrides);
221222
inputArgs.AddLastArg(arguments, options::OPT_typo_correction_limit);
222223
inputArgs.AddLastArg(arguments, options::OPT_enable_app_extension);

lib/Frontend/CompilerInvocation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
549549
}
550550
}
551551

552+
Opts.WarnConcurrency |= Args.hasArg(OPT_warn_concurrency);
553+
552554
Opts.WarnImplicitOverrides =
553555
Args.hasArg(OPT_warn_implicit_overrides);
554556

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -864,11 +864,19 @@ static bool diagnoseNonConcurrentProperty(
864864
return false;
865865
}
866866

867+
/// Whether we should diagnose cases where ConcurrentValue conformances are
868+
/// missing.
869+
static bool shouldDiagnoseNonConcurrentValueViolations(
870+
const LangOptions &langOpts) {
871+
return langOpts.EnableExperimentalConcurrency ||
872+
langOpts.WarnConcurrency;
873+
}
874+
867875
bool swift::diagnoseNonConcurrentTypesInReference(
868876
ConcreteDeclRef declRef, const DeclContext *dc, SourceLoc loc,
869877
ConcurrentReferenceKind refKind) {
870878
// Bail out immediately if we aren't supposed to do this checking.
871-
if (!dc->getASTContext().LangOpts.EnableExperimentalConcurrency)
879+
if (!shouldDiagnoseNonConcurrentValueViolations(dc->getASTContext().LangOpts))
872880
return false;
873881

874882
// For functions, check the parameter and result types.
@@ -1241,7 +1249,7 @@ namespace {
12411249
if (!indexExpr || !indexExpr->getType())
12421250
continue;
12431251

1244-
if (ctx.LangOpts.EnableExperimentalConcurrency &&
1252+
if (shouldDiagnoseNonConcurrentValueViolations(ctx.LangOpts) &&
12451253
!isConcurrentValueType(getDeclContext(), indexExpr->getType())) {
12461254
ctx.Diags.diagnose(
12471255
component.getLoc(), diag::non_concurrent_keypath_capture,
@@ -2671,6 +2679,9 @@ void swift::checkOverrideActorIsolation(ValueDecl *value) {
26712679
}
26722680

26732681
static bool shouldDiagnoseExistingDataRaces(const DeclContext *dc) {
2682+
if (dc->getASTContext().LangOpts.WarnConcurrency)
2683+
return true;
2684+
26742685
while (!dc->isModuleScopeContext()) {
26752686
if (auto closure = dyn_cast<AbstractClosureExpr>(dc)) {
26762687
// Async and concurrent closures use concurrency features.
@@ -2717,16 +2728,21 @@ static bool shouldDiagnoseExistingDataRaces(const DeclContext *dc) {
27172728
return false;
27182729
}
27192730

2720-
static DiagnosticBehavior toDiagnosticBehavior(ConcurrentValueCheck check,
2731+
static DiagnosticBehavior toDiagnosticBehavior(const LangOptions &langOpts,
2732+
ConcurrentValueCheck check,
27212733
bool diagnoseImplicit = false) {
27222734
switch (check) {
27232735
case ConcurrentValueCheck::ImpliedByStandardProtocol:
2724-
return DiagnosticBehavior::Warning;
2736+
return shouldDiagnoseNonConcurrentValueViolations(langOpts)
2737+
? DiagnosticBehavior::Warning
2738+
: DiagnosticBehavior::Ignore;
27252739
case ConcurrentValueCheck::Explicit:
27262740
return DiagnosticBehavior::Unspecified;
27272741
case ConcurrentValueCheck::Implicit:
2728-
return diagnoseImplicit ? DiagnosticBehavior::Unspecified
2729-
: DiagnosticBehavior::Ignore;
2742+
return (diagnoseImplicit &&
2743+
shouldDiagnoseNonConcurrentValueViolations(langOpts))
2744+
? DiagnosticBehavior::Unspecified
2745+
: DiagnosticBehavior::Ignore;
27302746
}
27312747
}
27322748

@@ -2736,7 +2752,8 @@ static bool checkConcurrentValueInstanceStorage(
27362752
NominalTypeDecl *nominal, DeclContext *dc, ConcurrentValueCheck check) {
27372753
// Stored properties of structs and classes must have
27382754
// ConcurrentValue-conforming types.
2739-
auto behavior = toDiagnosticBehavior(check);
2755+
const auto &langOpts = dc->getASTContext().LangOpts;
2756+
auto behavior = toDiagnosticBehavior(langOpts, check);
27402757
bool invalid = false;
27412758
if (isa<StructDecl>(nominal) || isa<ClassDecl>(nominal)) {
27422759
auto classDecl = dyn_cast<ClassDecl>(nominal);
@@ -2813,7 +2830,8 @@ bool swift::checkConcurrentValueConformance(
28132830

28142831
// ConcurrentValue can only be used in the same source file.
28152832
auto conformanceDecl = conformanceDC->getAsDecl();
2816-
auto behavior = toDiagnosticBehavior(check, /*diagnoseImplicit=*/true);
2833+
auto behavior = toDiagnosticBehavior(
2834+
nominal->getASTContext().LangOpts, check, /*diagnoseImplicit=*/true);
28172835
if (!conformanceDC->getParentSourceFile() ||
28182836
conformanceDC->getParentSourceFile() != nominal->getParentSourceFile()) {
28192837
conformanceDecl->diagnose(diag::concurrent_value_outside_source_file,

test/Constraints/ErrorBridging.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func throwErrorCode() throws {
7575
throw FictionalServerError.meltedDown // expected-error{{thrown error code type 'FictionalServerError.Code' does not conform to 'Error'; construct an 'FictionalServerError' instance}}{{29-29=(}}{{40-40=)}}
7676
}
7777

78-
class MyErrorClass { } // expected-warning{{non-final class 'MyErrorClass' cannot conform to `ConcurrentValue`; use `UnsafeConcurrentValue`}}
78+
class MyErrorClass { }
7979
extension MyErrorClass: Error { }
8080

8181
class MyClass { }

test/Constraints/casts.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ extension Int: JSONLeaf { }
346346
extension Array: JSON where Element: JSON { }
347347

348348
protocol SR13035Error: Error {}
349-
class ChildError: SR13035Error {} // expected-warning{{non-final class 'ChildError' cannot conform to `ConcurrentValue`; use `UnsafeConcurrentValue`}}
349+
class ChildError: SR13035Error {}
350350

351351
protocol AnyC {
352352
func foo()

test/SILGen/errors.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ class Cat {}
77
enum HomeworkError : Error {
88
case TooHard
99
case TooMuch
10-
case CatAteIt(Cat) // expected-warning{{associated value 'CatAteIt' of 'ConcurrentValue'-conforming enum 'HomeworkError' has non-concurrent-value type 'Cat'}}
11-
case CatHidIt(Cat) // expected-warning{{associated value 'CatHidIt' of 'ConcurrentValue'-conforming enum 'HomeworkError' has non-concurrent-value type 'Cat'}}
10+
case CatAteIt(Cat)
11+
case CatHidIt(Cat)
1212
}
1313

1414
func someValidPointer<T>() -> UnsafePointer<T> { fatalError() }
@@ -1013,14 +1013,14 @@ func testOptionalTryNeverFailsAddressOnlyVar<T>(_ obj: T) {
10131013
var copy = try? obj // expected-warning {{no calls to throwing functions occur within 'try' expression}} expected-warning {{initialization of variable 'copy' was never used; consider replacing with assignment to '_' or removing it}}
10141014
}
10151015

1016-
class SomeErrorClass : Error { } // expected-warning{{non-final class 'SomeErrorClass' cannot conform to `ConcurrentValue`; use `UnsafeConcurrentValue`}}
1016+
class SomeErrorClass : Error { }
10171017

10181018
// CHECK-LABEL: sil_vtable SomeErrorClass
10191019
// CHECK-NEXT: #SomeErrorClass.init!allocator: {{.*}} : @$s6errors14SomeErrorClassCACycfC
10201020
// CHECK-NEXT: #SomeErrorClass.deinit!deallocator: @$s6errors14SomeErrorClassCfD
10211021
// CHECK-NEXT: }
10221022

1023-
class OtherErrorSub : OtherError { } // expected-warning{{non-final class 'OtherErrorSub' cannot conform to `ConcurrentValue`; use `UnsafeConcurrentValue`}}
1023+
class OtherErrorSub : OtherError { }
10241024

10251025
// CHECK-LABEL: sil_vtable OtherErrorSub {
10261026
// CHECK-NEXT: #OtherError.init!allocator: {{.*}} : @$s6errors13OtherErrorSubCACycfC [override]

test/Sema/existential_nested_type.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ protocol HasAssoc {
1010
}
1111

1212
enum MyError : Error {
13-
case bad(Any) // expected-warning{{associated value 'bad' of 'ConcurrentValue'-conforming enum 'MyError' has non-concurrent-value type 'Any'}}
13+
case bad(Any)
1414
}
1515

1616
func checkIt(_ js: Any) throws {

test/decl/func/throwing_functions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ B(foo: 0) // expected-warning{{unused}}
145145

146146
// rdar://problem/33040113 - Provide fix-it for missing "try" when calling throwing Swift function
147147

148-
class E_33040113 : Error {} // expected-warning{{non-final class 'E_33040113' cannot conform to `ConcurrentValue`; use `UnsafeConcurrentValue`}}
148+
class E_33040113 : Error {}
149149
func rdar33040113() throws -> Int {
150150
throw E_33040113()
151151
}

0 commit comments

Comments
 (0)