Skip to content

Commit f440663

Browse files
authored
Merge pull request swiftlang#72247 from gottesmm/diagnostic-improvements
[region-isolation] Change "pass non-transferable non-sendable value as transferring parameter" error to use the variables name + some other small improvements
2 parents 49bf81b + aa9a2f6 commit f440663

7 files changed

+111
-62
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -939,8 +939,6 @@ ERROR(regionbasedisolation_unknown_pattern, none,
939939
// Old Transfer Non Sendable Diagnostics
940940
//
941941

942-
ERROR(regionbasedisolation_selforargtransferred, none,
943-
"call site passes `self` or a non-sendable argument of this function to another thread, potentially yielding a race with the caller", ())
944942
ERROR(regionbasedisolation_transfer_yields_race_no_isolation, none,
945943
"transferring value of non-Sendable type %0; later accesses could race",
946944
(Type))
@@ -957,8 +955,8 @@ ERROR(regionbasedisolation_arg_transferred, none,
957955
"%0 value of type %1 transferred to %2 context; later accesses to value could race",
958956
(StringRef, Type, ActorIsolation))
959957
ERROR(regionbasedisolation_arg_passed_to_strongly_transferred_param, none,
960-
"task-isolated value of type %0 passed as a strongly transferred parameter; later accesses could race",
961-
(Type))
958+
"%0 value of type %1 passed as a strongly transferred parameter; later accesses could race",
959+
(StringRef, Type))
962960
NOTE(regionbasedisolation_isolated_since_in_same_region_basename, none,
963961
"value is %0 since it is in the same region as %1",
964962
(StringRef, DeclBaseName))
@@ -973,9 +971,9 @@ ERROR(regionbasedisolation_named_transfer_yields_race, none,
973971
ERROR(regionbasedisolation_stronglytransfer_assignment_yields_race_name, none,
974972
"assigning %0 to transferring parameter %1 may cause a race",
975973
(Identifier, Identifier))
976-
NOTE(regionbasedisolation_stronglytransfer_taskisolated_assign_note, none,
977-
"%0 is a task-isolated value that is assigned into transferring parameter %1. Transferred uses of %1 may race with caller uses of %0",
978-
(Identifier, Identifier))
974+
NOTE(regionbasedisolation_named_transfer_into_transferring_param, none,
975+
"%0 %1 is passed as a transferring parameter; Uses in callee may race with later %0 uses",
976+
(StringRef, Identifier))
979977

980978
NOTE(regionbasedisolation_named_info_transfer_yields_race, none,
981979
"%0 is transferred from %1 caller to %2 callee. Later uses in caller could race with potential uses in callee",
@@ -991,6 +989,15 @@ NOTE(regionbasedisolation_named_arg_info, none,
991989
(Identifier))
992990
NOTE(regionbasedisolation_named_stronglytransferred_binding, none,
993991
"Cannot access a transferring parameter after the parameter has been transferred", ())
992+
NOTE(regionbasedisolation_note_arg_passed_to_strongly_transferred_param, none,
993+
"%0 value of type %1 passed as a strongly transferred parameter; later accesses could race",
994+
(StringRef, Identifier, Type))
995+
ERROR(regionbasedisolation_named_arg_passed_to_strongly_transferred_param, none,
996+
"%0 %1 passed as a strongly transferred parameter; Uses in callee could race with later %0 uses",
997+
(StringRef, Identifier))
998+
999+
ERROR(regionbasedisolation_task_or_actor_isolated_transferred, none,
1000+
"task or actor isolated value cannot be transferred", ())
9941001

9951002
// TODO: print the name of the nominal type
9961003
ERROR(deinit_not_visible, none,

lib/SILOptimizer/Mandatory/TransferNonSendable.cpp

Lines changed: 62 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -912,24 +912,25 @@ class TransferNonTransferrableDiagnosticEmitter {
912912
diag::regionbasedisolation_unknown_pattern);
913913
}
914914

915-
void emitMiscUses(SILLocation loc) {
916-
diagnoseError(loc, diag::regionbasedisolation_selforargtransferred);
915+
void emitUnknownUse(SILLocation loc) {
916+
// TODO: This will eventually be an unknown pattern error.
917+
diagnoseError(
918+
loc, diag::regionbasedisolation_task_or_actor_isolated_transferred);
917919
}
918920

919921
void emitFunctionArgumentApply(SILLocation loc, Type type,
920-
ValueIsolationRegionInfo regionInfo,
921922
ApplyIsolationCrossing crossing) {
922923
SmallString<64> descriptiveKindStr;
923924
{
924925
llvm::raw_svector_ostream os(descriptiveKindStr);
925-
regionInfo.printForDiagnostics(os);
926+
getIsolationRegionInfo().printForDiagnostics(os);
926927
}
927928
diagnoseError(loc, diag::regionbasedisolation_arg_transferred,
928929
StringRef(descriptiveKindStr), type,
929930
crossing.getCalleeIsolation())
930931
.highlight(getOperand()->getUser()->getLoc().getSourceRange());
931932

932-
if (regionInfo.isTaskIsolated()) {
933+
if (getIsolationRegionInfo().isTaskIsolated()) {
933934
auto *fArg =
934935
cast<SILFunctionArgument>(info.nonTransferrable.get<SILValue>());
935936
if (fArg->getDecl()) {
@@ -964,23 +965,46 @@ class TransferNonTransferrableDiagnosticEmitter {
964965

965966
void emitFunctionArgumentApplyStronglyTransferred(SILLocation loc,
966967
Type type) {
967-
diagnoseError(
968-
loc,
969-
diag::regionbasedisolation_arg_passed_to_strongly_transferred_param,
970-
type)
968+
SmallString<64> descriptiveKindStr;
969+
{
970+
llvm::raw_svector_ostream os(descriptiveKindStr);
971+
getIsolationRegionInfo().printForDiagnostics(os);
972+
}
973+
auto diag =
974+
diag::regionbasedisolation_arg_passed_to_strongly_transferred_param;
975+
diagnoseError(loc, diag, descriptiveKindStr, type)
976+
.highlight(getOperand()->getUser()->getLoc().getSourceRange());
977+
}
978+
979+
void emitNamedOnlyError(SILLocation loc, Identifier name) {
980+
diagnoseError(loc, diag::regionbasedisolation_named_transfer_yields_race,
981+
name)
971982
.highlight(getOperand()->getUser()->getLoc().getSourceRange());
972983
}
973984

974985
void emitNamedIsolation(SILLocation loc, Identifier name,
975986
ApplyIsolationCrossing isolationCrossing) {
976-
diagnoseError(loc, diag::regionbasedisolation_named_transfer_yields_race,
977-
name);
987+
emitNamedOnlyError(loc, name);
978988
diagnoseNote(
979989
loc, diag::regionbasedisolation_transfer_non_transferrable_named_note,
980990
name, isolationCrossing.getCallerIsolation(),
981991
isolationCrossing.getCalleeIsolation());
982992
}
983993

994+
void emitNamedFunctionArgumentApplyStronglyTransferred(
995+
SILLocation loc, Identifier varName,
996+
ValueIsolationRegionInfo isolationRegionInfo) {
997+
emitNamedOnlyError(loc, varName);
998+
SmallString<64> descriptiveKindStr;
999+
{
1000+
llvm::raw_svector_ostream os(descriptiveKindStr);
1001+
getIsolationRegionInfo().printForDiagnostics(os);
1002+
}
1003+
auto diag =
1004+
diag::regionbasedisolation_named_transfer_into_transferring_param;
1005+
diagnoseNote(loc, diag, descriptiveKindStr, varName);
1006+
}
1007+
9841008
private:
9851009
ASTContext &getASTContext() const {
9861010
return getOperand()->getFunction()->getASTContext();
@@ -1073,29 +1097,35 @@ bool TransferNonTransferrableDiagnosticInferrer::run() {
10731097
auto loc = op->getUser()->getLoc();
10741098

10751099
if (auto *sourceApply = loc.getAsASTNode<ApplyExpr>()) {
1076-
std::optional<ApplyIsolationCrossing> isolation = {};
1100+
// First see if we have a transferring argument.
1101+
if (auto fas = FullApplySite::isa(op->getUser())) {
1102+
if (fas.getArgumentParameterInfo(*op).hasOption(
1103+
SILParameterInfo::Transferring)) {
1104+
1105+
// See if we can infer a name from the value.
1106+
SmallString<64> resultingName;
1107+
if (auto varName = inferNameFromValue(op->get())) {
1108+
diagnosticEmitter.emitNamedFunctionArgumentApplyStronglyTransferred(
1109+
loc, *varName, diagnosticEmitter.getIsolationRegionInfo());
1110+
return true;
1111+
}
1112+
1113+
Type type = op->get()->getType().getASTType();
1114+
if (auto *inferredArgExpr =
1115+
inferArgumentExprFromApplyExpr(sourceApply, fas, op)) {
1116+
type = inferredArgExpr->findOriginalType();
1117+
}
1118+
diagnosticEmitter.emitFunctionArgumentApplyStronglyTransferred(loc,
1119+
type);
1120+
return true;
1121+
}
1122+
}
10771123

10781124
// First try to get the apply from the isolation crossing.
1079-
if (auto value = sourceApply->getIsolationCrossing())
1080-
isolation = value;
1125+
auto isolation = sourceApply->getIsolationCrossing();
10811126

10821127
// If we could not infer an isolation...
10831128
if (!isolation) {
1084-
// First see if we have a transferring argument.
1085-
if (auto fas = FullApplySite::isa(op->getUser())) {
1086-
if (fas.getArgumentParameterInfo(*op).hasOption(
1087-
SILParameterInfo::Transferring)) {
1088-
Type type = op->get()->getType().getASTType();
1089-
if (auto *inferredArgExpr =
1090-
inferArgumentExprFromApplyExpr(sourceApply, fas, op)) {
1091-
type = inferredArgExpr->findOriginalType();
1092-
}
1093-
diagnosticEmitter.emitFunctionArgumentApplyStronglyTransferred(loc,
1094-
type);
1095-
return true;
1096-
}
1097-
}
1098-
10991129
// Otherwise, emit a "we don't know error" that tells the user to file a
11001130
// bug.
11011131
diagnoseError(op->getUser(), diag::regionbasedisolation_unknown_pattern);
@@ -1120,9 +1150,7 @@ bool TransferNonTransferrableDiagnosticInferrer::run() {
11201150
}
11211151
}
11221152

1123-
auto isolationRegionInfo = diagnosticEmitter.getIsolationRegionInfo();
1124-
diagnosticEmitter.emitFunctionArgumentApply(loc, type, isolationRegionInfo,
1125-
*isolation);
1153+
diagnosticEmitter.emitFunctionArgumentApply(loc, type, *isolation);
11261154
return true;
11271155
}
11281156

@@ -1137,15 +1165,13 @@ bool TransferNonTransferrableDiagnosticInferrer::run() {
11371165
// See if we are in SIL and have an apply site specified isolation.
11381166
if (auto fas = FullApplySite::isa(op->getUser())) {
11391167
if (auto isolation = fas.getIsolationCrossing()) {
1140-
auto isolationRegionInfo = diagnosticEmitter.getIsolationRegionInfo();
11411168
diagnosticEmitter.emitFunctionArgumentApply(
1142-
loc, op->get()->getType().getASTType(), isolationRegionInfo,
1143-
*isolation);
1169+
loc, op->get()->getType().getASTType(), *isolation);
11441170
return true;
11451171
}
11461172
}
11471173

1148-
diagnosticEmitter.emitMiscUses(loc);
1174+
diagnosticEmitter.emitUnknownUse(loc);
11491175
return true;
11501176
}
11511177

test/Concurrency/issue-57376.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,35 +26,35 @@ func testAsyncSequence1Sendable<Seq: AsyncSequence>(_ seq: Seq) async throws whe
2626
}
2727

2828
func testAsyncSequenceTypedPattern<Seq: AsyncSequence>(_ seq: Seq) async throws where Seq.Element == Int { // expected-targeted-and-complete-note {{consider making generic parameter 'Seq' conform to the 'Sendable' protocol}} {{54-54=, Sendable}}
29-
async let result: Int = seq.reduce(0) { $0 + $1 } // expected-tns-warning {{call site passes `self` or a non-sendable argument of this function to another thread, potentially yielding a race with the caller}}
29+
async let result: Int = seq.reduce(0) { $0 + $1 } // expected-tns-warning {{task or actor isolated value cannot be transferred}}
3030
// expected-warning @-1 {{immutable value 'result' was never used; consider replacing with '_' or removing it}}
3131
// expected-targeted-and-complete-warning @-2 {{capture of 'seq' with non-sendable type 'Seq' in 'async let' binding}}
3232
}
3333

3434
func testAsyncSequenceTypedPattern1<Seq: AsyncSequence>(_ seq: Seq) async throws where Seq.Element == Int { // expected-targeted-and-complete-note {{consider making generic parameter 'Seq' conform to the 'Sendable' protocol}} {{55-55=, Sendable}}
35-
async let _: Int = seq.reduce(0) { $0 + $1 } // expected-tns-warning {{call site passes `self` or a non-sendable argument of this function to another thread, potentially yielding a race with the caller}}
35+
async let _: Int = seq.reduce(0) { $0 + $1 } // expected-tns-warning {{task or actor isolated value cannot be transferred}}
3636
// expected-targeted-and-complete-warning @-1 {{capture of 'seq' with non-sendable type 'Seq' in 'async let' binding}}
3737
}
3838

3939
func testAsyncSequence<Seq: AsyncSequence>(_ seq: Seq) async throws where Seq.Element == Int { // expected-targeted-and-complete-note {{consider making generic parameter 'Seq' conform to the 'Sendable' protocol}} {{42-42=, Sendable}}
40-
async let result = seq.reduce(0) { $0 + $1 } // expected-tns-warning {{call site passes `self` or a non-sendable argument of this function to another thread, potentially yielding a race with the caller}}
40+
async let result = seq.reduce(0) { $0 + $1 } // // expected-tns-warning {{task or actor isolated value cannot be transferred}}
4141
// expected-warning @-1 {{initialization of immutable value 'result' was never used; consider replacing with assignment to '_' or removing it}}
4242
// expected-targeted-and-complete-warning @-2 {{capture of 'seq' with non-sendable type 'Seq' in 'async let' binding}}
4343
}
4444

4545
func testAsyncSequence1<Seq: AsyncSequence>(_ seq: Seq) async throws where Seq.Element == Int { // expected-targeted-and-complete-note {{consider making generic parameter 'Seq' conform to the 'Sendable' protocol}} {{43-43=, Sendable}}
46-
async let _ = seq.reduce(0) { $0 + $1 } // expected-tns-warning {{call site passes `self` or a non-sendable argument of this function to another thread, potentially yielding a race with the caller}}
46+
async let _ = seq.reduce(0) { $0 + $1 } // // expected-tns-warning {{task or actor isolated value cannot be transferred}}
4747
// expected-targeted-and-complete-warning @-1 {{capture of 'seq' with non-sendable type 'Seq' in 'async let' binding}}
4848
}
4949

5050
func testAsyncSequence3<Seq>(_ seq: Seq) async throws where Seq: AsyncSequence, Seq.Element == Int { // expected-targeted-and-complete-note {{consider making generic parameter 'Seq' conform to the 'Sendable' protocol}} {{28-28=: Sendable}}
51-
async let result = seq // expected-tns-warning {{call site passes `self` or a non-sendable argument of this function to another thread, potentially yielding a race with the caller}}
51+
async let result = seq // // expected-tns-warning {{task or actor isolated value cannot be transferred}}
5252
// expected-targeted-and-complete-warning @-1 {{capture of 'seq' with non-sendable type 'Seq' in 'async let' binding}}
5353
//expected-warning @-2 {{initialization of immutable value 'result' was never used; consider replacing with assignment to '_' or removing it}}
5454
}
5555

5656
func testAsyncSequence4<Seq>(_ seq: Seq) async throws where Seq: AsyncSequence, Seq.Element == Int { // expected-targeted-and-complete-note {{consider making generic parameter 'Seq' conform to the 'Sendable' protocol}} {{28-28=: Sendable}}
57-
async let _ = seq // expected-tns-warning {{call site passes `self` or a non-sendable argument of this function to another thread, potentially yielding a race with the caller}}
57+
async let _ = seq // // expected-tns-warning {{task or actor isolated value cannot be transferred}}
5858
// expected-targeted-and-complete-warning @-1 {{capture of 'seq' with non-sendable type 'Seq' in 'async let' binding}}
5959
}
6060

test/Concurrency/transfernonsendable.sil

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -222,39 +222,39 @@ bb0(%0 : @guaranteed $NonSendableStruct):
222222
debug_value %0 : $NonSendableStruct, var, name "myname"
223223
%2 = struct_extract %0 : $NonSendableStruct, #NonSendableStruct.ns
224224
%3 = copy_value %2 : $NonSendableKlass
225-
return %3 : $NonSendableKlass // expected-warning {{call site passes `self`}}
225+
return %3 : $NonSendableKlass // expected-warning {{task or actor isolated value cannot be transferred}}
226226
}
227227

228228
sil [ossa] @synchronous_returns_transferring_globalactor_struct_structextract : $@convention(method) (@guaranteed MainActorIsolatedStruct) -> @sil_transferring @owned NonSendableKlass {
229229
bb0(%0 : @guaranteed $MainActorIsolatedStruct):
230230
debug_value %0 : $MainActorIsolatedStruct, var, name "myname"
231231
%2 = struct_extract %0 : $MainActorIsolatedStruct, #MainActorIsolatedStruct.ns
232232
%3 = copy_value %2 : $NonSendableKlass
233-
return %3 : $NonSendableKlass // expected-warning {{call site passes `self`}}
233+
return %3 : $NonSendableKlass // expected-warning {{task or actor isolated value cannot be transferred}}
234234
}
235235

236236
sil [ossa] @synchronous_returns_transferring_globalactor_struct_structelementaddr : $@convention(method) (@in_guaranteed MainActorIsolatedStruct) -> @sil_transferring @owned NonSendableKlass {
237237
bb0(%0 : $*MainActorIsolatedStruct):
238238
debug_value %0 : $*MainActorIsolatedStruct, var, name "myname"
239239
%2 = struct_element_addr %0 : $*MainActorIsolatedStruct, #MainActorIsolatedStruct.ns
240240
%3 = load [copy] %2 : $*NonSendableKlass
241-
return %3 : $NonSendableKlass // expected-warning {{call site passes `self`}}
241+
return %3 : $NonSendableKlass // expected-warning {{task or actor isolated value cannot be transferred}}
242242
}
243243

244244
sil [ossa] @synchronous_returns_transferring_globalactor_enum_uncheckedenumdata : $@convention(method) (@guaranteed MainActorIsolatedEnum) -> @sil_transferring @owned NonSendableKlass {
245245
bb0(%0 : @guaranteed $MainActorIsolatedEnum):
246246
debug_value %0 : $MainActorIsolatedEnum, var, name "myname"
247247
%2 = unchecked_enum_data %0 : $MainActorIsolatedEnum, #MainActorIsolatedEnum.second!enumelt
248248
%3 = copy_value %2 : $NonSendableKlass
249-
return %3 : $NonSendableKlass // expected-warning {{call site passes `self`}}
249+
return %3 : $NonSendableKlass // expected-warning {{task or actor isolated value cannot be transferred}}
250250
}
251251

252252
sil [ossa] @synchronous_returns_transferring_globalactor_enum_uncheckedtakeenumdataaddr : $@convention(method) (@in MainActorIsolatedEnum) -> @sil_transferring @owned NonSendableKlass {
253253
bb0(%0 : $*MainActorIsolatedEnum):
254254
debug_value %0 : $*MainActorIsolatedEnum, var, name "myname"
255255
%2 = unchecked_take_enum_data_addr %0 : $*MainActorIsolatedEnum, #MainActorIsolatedEnum.second!enumelt
256256
%3 = load [take] %2 : $*NonSendableKlass
257-
return %3 : $NonSendableKlass // expected-warning {{call site passes `self`}}
257+
return %3 : $NonSendableKlass // expected-warning {{task or actor isolated value cannot be transferred}}
258258
}
259259

260260
sil [ossa] @synchronous_returns_transferring_globalactor_enum_switchenum : $@convention(method) (@guaranteed MainActorIsolatedEnum) -> @sil_transferring @owned FakeOptional<NonSendableKlass> {
@@ -272,7 +272,7 @@ bb2(%1 : @guaranteed $NonSendableKlass):
272272
br bb3(%3 : $FakeOptional<NonSendableKlass>)
273273

274274
bb3(%4 : @owned $FakeOptional<NonSendableKlass>):
275-
return %4 : $FakeOptional<NonSendableKlass> // expected-warning {{call site passes `self`}}
275+
return %4 : $FakeOptional<NonSendableKlass> // expected-warning {{task or actor isolated value cannot be transferred}}
276276
}
277277

278278
sil [ossa] @warningIfCallingGetter : $@convention(method) @async (@sil_isolated @guaranteed MyActor) -> () {

test/Concurrency/transfernonsendable_strong_transferring_params.swift

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -333,10 +333,19 @@ func testTransferOtherParamTuple(_ x: transferring Klass, y: (Klass, Klass)) asy
333333
x = y.0
334334
}
335335

336-
func useSugaredTypeNameWhenEmittingTaskIsolationError(_ x: @escaping @MainActor () async -> ()) {
336+
func taskIsolatedError(_ x: @escaping @MainActor () async -> ()) {
337337
func fakeInit(operation: transferring @escaping () async -> ()) {}
338338

339-
fakeInit(operation: x) // expected-warning {{task-isolated value of type '@MainActor () async -> ()' passed as a strongly transferred parameter}}
339+
fakeInit(operation: x) // expected-warning {{transferring 'x' may cause a race}}
340+
// expected-note @-1 {{task-isolated 'x' is passed as a transferring parameter; Uses in callee may race with later task-isolated uses}}
341+
}
342+
343+
@MainActor func actorIsolatedError(_ x: @escaping @MainActor () async -> ()) {
344+
func fakeInit(operation: transferring @escaping () async -> ()) {}
345+
346+
// TODO: This needs to say actor-isolated.
347+
fakeInit(operation: x) // expected-warning {{transferring 'x' may cause a race}}
348+
// expected-note @-1 {{task-isolated 'x' is passed as a transferring parameter; Uses in callee may race with later task-isolated uses}}
340349
}
341350

342351
// Make sure we error here on only the second since x by being assigned a part
@@ -348,3 +357,9 @@ func testMergeWithTaskIsolated(_ x: transferring Klass, y: Klass) async {
348357
await transferToMain(x) // expected-warning {{transferring 'x' may cause a race}}
349358
// expected-note @-1 {{transferring nonisolated 'x' to main actor-isolated callee could cause races between main actor-isolated and nonisolated uses}}
350359
}
360+
361+
@MainActor func testMergeWithActorIsolated(_ x: transferring Klass, y: Klass) async {
362+
x = y
363+
await transferToCustom(x) // expected-warning {{transferring 'x' may cause a race}}
364+
// expected-note @-1 {{transferring main actor-isolated 'x' to global actor 'CustomActor'-isolated callee could cause races between global actor 'CustomActor'-isolated and main actor-isolated uses}}
365+
}

0 commit comments

Comments
 (0)