Skip to content

Commit 6eb31b4

Browse files
committed
[region-isolation] Assigning into a transferring parameter should be a store, not a transfer.
rdar://123865943
1 parent be1551f commit 6eb31b4

File tree

5 files changed

+53
-167
lines changed

5 files changed

+53
-167
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -950,9 +950,6 @@ ERROR(regionbasedisolation_transfer_yields_race_with_isolation, none,
950950
ERROR(regionbasedisolation_isolated_capture_yields_race, none,
951951
"%1 closure captures value of non-Sendable type %0 from %2 context; later accesses to value could race",
952952
(Type, ActorIsolation, ActorIsolation))
953-
ERROR(regionbasedisolation_transfer_yields_race_transferring_parameter, none,
954-
"transferring value of non-Sendable type %0 into transferring parameter; later accesses could race",
955-
(Type))
956953
ERROR(regionbasedisolation_transfer_yields_race_stronglytransferred_binding, none,
957954
"binding of non-Sendable type %0 accessed after being transferred; later accesses could race",
958955
(Type))

lib/SILOptimizer/Analysis/RegionAnalysis.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1986,16 +1986,6 @@ class PartitionOpTranslator {
19861986
SILValue srcValue = src->get();
19871987

19881988
if (auto nonSendableDest = tryToTrackValue(destValue)) {
1989-
// Before we do anything check if we have an assignment into an
1990-
// alloc_stack for a consuming transferring parameter... in such a case,
1991-
// we need to handle this specially.
1992-
if (nonSendableDest->isTransferringParameter()) {
1993-
if (auto nonSendableSrc = tryToTrackValue(srcValue)) {
1994-
return translateSILAssignmentToTransferringParameter(
1995-
*nonSendableDest, dest, *nonSendableSrc, src);
1996-
}
1997-
}
1998-
19991989
// In the following situations, we can perform an assign:
20001990
//
20011991
// 1. A store to unaliased storage.

lib/SILOptimizer/Mandatory/TransferNonSendable.cpp

Lines changed: 5 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -442,10 +442,6 @@ class UseAfterTransferDiagnosticInferrer {
442442
/// error though.
443443
TypedRaceWithoutKnownIsolationCrossing = 2,
444444

445-
/// Used if the error is due to a transfer into an assignment into a
446-
/// transferring parameter.
447-
AssignmentIntoTransferringParameter = 3,
448-
449445
/// Set to true if this is a use of a normal value that was strongly
450446
/// transferred.
451447
UseOfStronglyTransferredValue = 4,
@@ -501,14 +497,6 @@ class UseAfterTransferDiagnosticInferrer {
501497
{}, inferredType, SILLocation::invalid());
502498
}
503499

504-
static UseDiagnosticInfo
505-
forTypedAssignmentIntoTransferringParameter(SILLocation loc,
506-
Type inferredType) {
507-
return UseDiagnosticInfo(
508-
UseDiagnosticInfoKind::AssignmentIntoTransferringParameter, loc, {},
509-
inferredType, SILLocation::invalid());
510-
}
511-
512500
static UseDiagnosticInfo
513501
forTypedUseOfStronglyTransferredValue(SILLocation loc, Type inferredType) {
514502
return UseDiagnosticInfo(
@@ -578,12 +566,6 @@ class UseAfterTransferDiagnosticInferrer {
578566
void initForApply(const Operand *op, ApplyExpr *expr);
579567
void initForAutoclosure(const Operand *op, AutoClosureExpr *expr);
580568

581-
void initForAssignmentToTransferringParameter(const Operand *op) {
582-
appendUseInfo(
583-
UseDiagnosticInfo::forTypedAssignmentIntoTransferringParameter(
584-
baseLoc, op->get()->getType().getASTType()));
585-
}
586-
587569
void initForUseOfStronglyTransferredValue(const Operand *op) {
588570
appendUseInfo(UseDiagnosticInfo::forTypedUseOfStronglyTransferredValue(
589571
baseLoc, op->get()->getType().getASTType()));
@@ -726,31 +708,11 @@ struct UseAfterTransferDiagnosticInferrer::Walker : ASTWalker {
726708
}
727709
};
728710

729-
static SILValue getDestOfStoreOrCopyAddr(Operand *op) {
730-
if (auto *si = dyn_cast<StoreInst>(op->getUser()))
731-
return si->getDest();
732-
733-
if (auto *copyAddr = dyn_cast<CopyAddrInst>(op->getUser()))
734-
return copyAddr->getDest();
735-
736-
return SILValue();
737-
}
738-
739711
void UseAfterTransferDiagnosticInferrer::init(const Operand *op) {
740712
baseLoc = op->getUser()->getLoc();
741713
baseInferredType = op->get()->getType().getASTType();
742714
auto *nonConstOp = const_cast<Operand *>(op);
743715

744-
// Before we do anything, see if the transfer instruction was into a
745-
// transferring parameter alloc_stack. In such a case, we emit a special
746-
// message.
747-
if (auto destValue = getDestOfStoreOrCopyAddr(nonConstOp)) {
748-
auto trackedValue = valueMap.getTrackableValue(destValue);
749-
if (trackedValue.isTransferringParameter()) {
750-
return initForAssignmentToTransferringParameter(op);
751-
}
752-
}
753-
754716
// Otherwise, see if our operand's instruction is a transferring parameter.
755717
if (auto fas = FullApplySite::isa(nonConstOp->getUser())) {
756718
assert(!fas.getArgumentConvention(*nonConstOp).isIndirectOutParameter() &&
@@ -831,8 +793,8 @@ void TransferNonSendableImpl::emitUseAfterTransferDiagnostics() {
831793
if (transferOpToRequireInstMultiMap.empty())
832794
return;
833795

834-
LLVM_DEBUG(llvm::dbgs()
835-
<< "Visiting found transfer+[requireInsts] for diagnostics.\n");
796+
LLVM_DEBUG(llvm::dbgs() << "Emitting use after transfer diagnostics.\n");
797+
836798
auto &astContext = regionInfo->getFunction()->getASTContext();
837799
for (auto [transferOp, requireInsts] :
838800
transferOpToRequireInstMultiMap.getRange()) {
@@ -940,14 +902,6 @@ void TransferNonSendableImpl::emitUseAfterTransferDiagnostics() {
940902
info.getInferredType())
941903
.highlight(info.getLoc().getSourceRange());
942904
break;
943-
case UseDiagnosticInfoKind::AssignmentIntoTransferringParameter:
944-
diagnoseError(
945-
astContext, info.getLoc(),
946-
diag::
947-
regionbasedisolation_transfer_yields_race_transferring_parameter,
948-
info.getInferredType())
949-
.highlight(info.getLoc().getSourceRange());
950-
break;
951905
case UseDiagnosticInfoKind::TypedIsolationCrossingDueToCapture:
952906
auto isolation = info.getIsolationCrossing();
953907
diagnoseError(astContext, info.getLoc(),
@@ -995,10 +949,6 @@ class TransferNonTransferrableDiagnosticInferrer {
995949

996950
/// Used if we have a named variable.
997951
NamedIsolation = 5,
998-
999-
/// Used if a non-transferring function argument is assigned to a
1000-
/// transferring function argument.
1001-
FunctionArgumentAssignedToStronglyTransferredParam = 6,
1002952
};
1003953

1004954
class UseDiagnosticInfo {
@@ -1047,16 +997,6 @@ class TransferNonTransferrableDiagnosticInferrer {
1047997
inferredType};
1048998
}
1049999

1050-
static UseDiagnosticInfo
1051-
forFunctionArgumentAssignedToStronglyTransferredParam(
1052-
Identifier funcArgName, Identifier transferredParam) {
1053-
return {UseDiagnosticInfoKind::
1054-
FunctionArgumentAssignedToStronglyTransferredParam,
1055-
{},
1056-
funcArgName,
1057-
transferredParam};
1058-
}
1059-
10601000
private:
10611001
UseDiagnosticInfo(
10621002
UseDiagnosticInfoKind kind,
@@ -1069,15 +1009,14 @@ class TransferNonTransferrableDiagnosticInferrer {
10691009
};
10701010

10711011
private:
1072-
RegionAnalysisValueMap &valueMap;
10731012
TransferredNonTransferrableInfo info;
10741013
std::optional<UseDiagnosticInfo> diagnosticInfo;
10751014
SourceLoc loc;
10761015

10771016
public:
10781017
TransferNonTransferrableDiagnosticInferrer(
1079-
RegionAnalysisValueMap &valueMap, TransferredNonTransferrableInfo info)
1080-
: valueMap(valueMap), info(info),
1018+
TransferredNonTransferrableInfo info)
1019+
: info(info),
10811020
loc(info.transferredOperand->getUser()->getLoc().getSourceLoc()) {}
10821021

10831022
/// Gathers diagnostics. Returns false if we emitted a "I don't understand
@@ -1122,28 +1061,6 @@ bool TransferNonTransferrableDiagnosticInferrer::run() {
11221061
auto *op = info.transferredOperand;
11231062
auto loc = info.transferredOperand->getUser()->getLoc();
11241063

1125-
// Before we do anything, see if the transfer instruction was into a
1126-
// transferring parameter alloc_stack. In such a case, we emit a special
1127-
// message.
1128-
if (auto destValue = getDestOfStoreOrCopyAddr(op)) {
1129-
auto trackedValue = valueMap.getTrackableValue(destValue);
1130-
if (trackedValue.isTransferringParameter()) {
1131-
auto valueName = inferNameFromValue(op->get());
1132-
auto paramName =
1133-
inferNameFromValue(trackedValue.getRepresentative().getValue());
1134-
if (!valueName || !paramName) {
1135-
diagnoseError(op->getUser(),
1136-
diag::regionbasedisolation_unknown_pattern);
1137-
return false;
1138-
}
1139-
1140-
diagnosticInfo = UseDiagnosticInfo::
1141-
forFunctionArgumentAssignedToStronglyTransferredParam(*valueName,
1142-
*paramName);
1143-
return true;
1144-
}
1145-
}
1146-
11471064
if (auto *sourceApply = loc.getAsASTNode<ApplyExpr>()) {
11481065
std::optional<ApplyIsolationCrossing> isolation = {};
11491066

@@ -1233,8 +1150,7 @@ void TransferNonSendableImpl::emitTransferredNonTransferrableDiagnostics() {
12331150
auto &astContext = regionInfo->getFunction()->getASTContext();
12341151
for (auto info : transferredNonTransferrable) {
12351152
auto *op = info.transferredOperand;
1236-
TransferNonTransferrableDiagnosticInferrer diagnosticInferrer(
1237-
regionInfo->getValueMap(), info);
1153+
TransferNonTransferrableDiagnosticInferrer diagnosticInferrer(info);
12381154
if (!diagnosticInferrer.run())
12391155
continue;
12401156

@@ -1306,20 +1222,6 @@ void TransferNonSendableImpl::emitTransferredNonTransferrableDiagnostics() {
13061222
diagnosticInfo.getIsolationCrossing().getCallerIsolation(),
13071223
diagnosticInfo.getIsolationCrossing().getCalleeIsolation());
13081224
break;
1309-
case UseDiagnosticInfoKind::
1310-
FunctionArgumentAssignedToStronglyTransferredParam:
1311-
diagnoseError(
1312-
astContext, loc,
1313-
diag::
1314-
regionbasedisolation_stronglytransfer_assignment_yields_race_name,
1315-
diagnosticInfo.getName(),
1316-
diagnosticInfo.getTransferredParamIdentifier());
1317-
diagnoseNote(
1318-
astContext, loc,
1319-
diag::regionbasedisolation_stronglytransfer_taskisolated_assign_note,
1320-
diagnosticInfo.getName(),
1321-
diagnosticInfo.getTransferredParamIdentifier());
1322-
break;
13231225
}
13241226
}
13251227
}

test/Concurrency/transfernonsendable_strong_transferring_params.swift

Lines changed: 44 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -195,47 +195,58 @@ func canTransferAssigningIntoLocal2(_ x: transferring Klass) async {
195195
// MARK: Transferring is "var" like //
196196
//////////////////////////////////////
197197

198-
// Assigning into a transferring parameter is a transfer!
199-
func assigningIsATransfer(_ x: transferring Klass) async {
200-
// Ok, this is disconnected.
198+
// Assigning into a transferring parameter is a merge.
199+
func assigningIsAMerge(_ x: transferring Klass) async {
201200
let y = Klass()
202201

203-
// y is transferred into x.
204-
x = y // expected-warning {{transferring value of non-Sendable type 'Klass' into transferring parameter; later accesses could race}}
202+
x = y
205203

206-
// Since y is now in x, we can't use y anymore so we emit an error.
207-
useValue(y) // expected-note {{access here could race}}
204+
// We can still transfer y since x is disconnected.
205+
await transferToMain(y)
208206
}
209207

210-
func assigningIsATransferNoError(_ x: transferring Klass) async {
211-
// Ok, this is disconnected.
208+
func assigningIsAMergeError(_ x: transferring Klass) async {
212209
let y = Klass()
213210

214-
// y is transferred into x.
215211
x = y
216212

217-
useValue(x)
213+
// We can still transfer y since x is disconnected.
214+
await transferToMain(y) // expected-warning {{transferring value of non-Sendable type 'Klass' from nonisolated context to main actor-isolated context}}
215+
216+
useValue(x) // expected-note {{access here could race}}
218217
}
219218

220-
func assigningIsATransferAny(_ x: transferring Any) async {
219+
func assigningIsAMergeAny(_ x: transferring Any) async {
221220
// Ok, this is disconnected.
222221
let y = getAny()
223222

224-
// y is transferred into x.
225-
x = y // expected-warning {{transferring value of non-Sendable type 'Any' into transferring parameter; later accesses could race}}
223+
x = y
224+
225+
await transferToMain(y)
226+
}
227+
228+
func assigningIsAMergeAnyError(_ x: transferring Any) async {
229+
// Ok, this is disconnected.
230+
let y = getAny() // expected-note {{variable defined here}}
226231

227-
// Since y is now in x, we can't use y anymore so we emit an error.
228-
useValue(y) // expected-note {{access here could race}}
232+
x = y
233+
234+
await transferToMain(y) // expected-warning {{transferring 'y' may cause a race}}
235+
// expected-note @-1 {{'y' is transferred from nonisolated caller to main actor-isolated callee}}
236+
237+
useValue(x) // expected-note {{access here could race}}
229238
}
230239

231240
func canTransferAfterAssign(_ x: transferring Any) async {
232241
// Ok, this is disconnected.
233242
let y = getAny()
234243

235244
// y is transferred into x.
245+
await transferToMain(x)
246+
236247
x = y
237248

238-
await transferToMain(x)
249+
useValue(x)
239250
}
240251

241252
func canTransferAfterAssignButUseIsError(_ x: transferring Any) async {
@@ -281,10 +292,10 @@ func mergeDoesNotEliminateEarlierTransfer(_ x: transferring NonSendableStruct) a
281292
await transferToMain(x) // expected-warning {{transferring 'x' may cause a race}}
282293
// expected-note @-1 {{'x' is transferred from nonisolated caller to main actor-isolated callee. Later uses in caller could race with potential uses in callee}}
283294

284-
// y is assigned into a field of x, so we treat this like a merge.
285-
x.first = y
295+
// y is assigned into a field of x.
296+
x.first = y // expected-note {{access here could race}}
286297

287-
useValue(x) // expected-note {{access here could race}}
298+
useValue(x)
288299
}
289300

290301
func mergeDoesNotEliminateEarlierTransfer2(_ x: transferring NonSendableStruct) async {
@@ -299,12 +310,7 @@ func mergeDoesNotEliminateEarlierTransfer2(_ x: transferring NonSendableStruct)
299310
await transferToMain(x) // expected-warning {{transferring 'x' may cause a race}}
300311
// expected-note @-1 {{'x' is transferred from nonisolated caller to main actor-isolated callee. Later uses in caller could race with potential uses in callee}}
301312

302-
// y is assigned into a field of x, so we treat this like a merge.
303-
x.first = y // expected-warning {{transferring value of non-Sendable type 'Klass' into transferring parameter; later accesses could race}}
304-
305-
useValue(x) // expected-note {{access here could race}}
306-
307-
useValue(y) // expected-note {{access here could race}}
313+
x.first = y // expected-note {{access here could race}}
308314
}
309315

310316
func doubleArgument() async {
@@ -320,34 +326,25 @@ func testTransferSrc(_ x: transferring Klass) async {
320326
}
321327

322328
func testTransferOtherParam(_ x: transferring Klass, y: Klass) async {
323-
x = y // expected-warning {{assigning 'y' to transferring parameter 'x' may cause a race}}
324-
// expected-note @-1 {{'y' is a task isolated value that is assigned into transferring parameter 'x'. Transferred uses of 'x' may race with caller uses of 'y'}}
329+
x = y
325330
}
326331

327332
func testTransferOtherParamTuple(_ x: transferring Klass, y: (Klass, Klass)) async {
328-
x = y.0 // expected-warning {{assigning 'y.0' to transferring parameter 'x' may cause a race}}
329-
// expected-note @-1 {{'y.0' is a task isolated value that is assigned into transferring parameter 'x'. Transferred uses of 'x' may race with caller uses of 'y.0'}}
330-
}
331-
332-
func testTransferOtherParamStruct(_ x: transferring Klass, y: NonSendableStruct) async {
333-
x = y.first // expected-warning {{assigning 'y.first' to transferring parameter 'x' may cause a race}}
334-
// expected-note @-1 {{'y.first' is a task isolated value that is assigned into transferring parameter 'x'. Transferred uses of 'x' may race with caller uses of 'y.first'}}
335-
}
336-
337-
func testTransferOtherParamTupleStruct(_ x: transferring Klass, y: (NonSendableStruct, NonSendableStruct)) async {
338-
x = y.1.second // expected-warning {{assigning 'y.1.second' to transferring parameter 'x' may cause a race}}
339-
// expected-note @-1 {{'y.1.second' is a task isolated value that is assigned into transferring parameter 'x'. Transferred uses of 'x' may race with caller uses of 'y.1.second'}}
340-
}
341-
342-
func testTransferOtherParamClassStructTuple(_ x: transferring Klass, y: KlassWithNonSendableStructPair) async {
343-
x = y.ns1.second // expected-warning {{assigning 'y.ns1.second' to transferring parameter 'x' may cause a race}}
344-
// expected-note @-1 {{'y.ns1.second' is a task isolated value that is assigned into transferring parameter 'x'}}
345-
x = y.ns2.1.second // expected-warning {{assigning 'y.ns2.1.second' to transferring parameter 'x' may cause a race}}
346-
// expected-note @-1 {{'y.ns2.1.second' is a task isolated value that is assigned into transferring parameter 'x'. Transferred uses of 'x' may race with caller uses of 'y.ns2.1.second'}}
333+
x = y.0
347334
}
348335

349336
func useSugaredTypeNameWhenEmittingTaskIsolationError(_ x: @escaping @MainActor () async -> ()) {
350337
func fakeInit(operation: transferring @escaping () async -> ()) {}
351338

352339
fakeInit(operation: x) // expected-warning {{task isolated value of type '@MainActor () async -> ()' passed as a strongly transferred parameter}}
353340
}
341+
342+
// Make sure we error here on only the second since x by being assigned a part
343+
// of y becomes task isolated
344+
func testMergeWithTaskIsolated(_ x: transferring Klass, y: Klass) async {
345+
await transferToMain(x)
346+
x = y
347+
// TODO: We need to say that this is task isolated.
348+
await transferToMain(x) // expected-warning {{transferring 'x' may cause a race}}
349+
// expected-note @-1 {{transferring nonisolated 'x' to main actor-isolated callee could cause races between main actor-isolated and nonisolated uses}}
350+
}

test/Concurrency/transfernonsendable_warning_until_swift6.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ func testPassArgumentAsTransferringParameter(_ x: NonSendableType) async {
3434

3535
func testAssignmentIntoTransferringParameter(_ x: transferring NonSendableType) async {
3636
let y = NonSendableType()
37-
x = y // expected-error {{transferring value of non-Sendable type 'NonSendableType' into transferring parameter; later accesses could race}}
38-
useValue(y) // expected-note {{access here could race}}
37+
await transferToMain(x)
38+
x = y
39+
useValue(y)
3940
}
4041

4142
func testAssigningParameterIntoTransferringParameter(_ x: transferring NonSendableType, _ y: NonSendableType) async {
42-
x = y // expected-error {{assigning 'y' to transferring parameter 'x' may cause a race}}
43-
// expected-note @-1 {{'y' is a task isolated value that is assigned into transferring parameter 'x'. Transferred uses of 'x' may race with caller uses of 'y'}}
43+
x = y
4444
}
4545

4646
func testIsolationCrossingDueToCapture() async {

0 commit comments

Comments
 (0)