Skip to content

Commit 60ba53c

Browse files
authored
Merge pull request swiftlang#76234 from gottesmm/pr-3cfcc173e99fd3e7aa08ddb66b5e28ac5b3e9704
[region-isolation] Do not allow for a disconnected value passed as an explicitly sent parameter to be reused.
2 parents f81d2e6 + eda603d commit 60ba53c

File tree

3 files changed

+81
-6
lines changed

3 files changed

+81
-6
lines changed

include/swift/SILOptimizer/Utils/PartitionUtils.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,11 +1226,17 @@ struct PartitionOpEvaluator {
12261226
}
12271227

12281228
// Next see if we are disconnected and have the same isolation. In such a
1229-
// case, we do not transfer since the disconnected value is allowed to be
1230-
// resued after we return.
1231-
if (transferredRegionIsolation.isDisconnected() && calleeIsolationInfo &&
1232-
transferredRegionIsolation.hasSameIsolation(calleeIsolationInfo))
1233-
return;
1229+
// case, if we are not marked explicitly as sending, we do not transfer
1230+
// since the disconnected value is allowed to be resued after we
1231+
// return. If we are passed as a sending parameter, we cannot do this.
1232+
if (auto *sourceInst = Impl::getSourceInst(op)) {
1233+
if (auto fas = FullApplySite::isa(sourceInst);
1234+
(!fas || !fas.isSending(*op.getSourceOp())) &&
1235+
transferredRegionIsolation.isDisconnected() &&
1236+
calleeIsolationInfo &&
1237+
transferredRegionIsolation.hasSameIsolation(calleeIsolationInfo))
1238+
return;
1239+
}
12341240

12351241
// Mark op.getOpArgs()[0] as transferred.
12361242
TransferringOperandState &state = operandToStateMap.get(op.getSourceOp());
@@ -1578,6 +1584,9 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
15781584

15791585
static SILLocation getLoc(SILInstruction *inst) { return inst->getLoc(); }
15801586
static SILLocation getLoc(Operand *op) { return op->getUser()->getLoc(); }
1587+
static SILInstruction *getSourceInst(const PartitionOp &partitionOp) {
1588+
return partitionOp.getSourceInst();
1589+
}
15811590
static SILIsolationInfo getIsolationInfo(const PartitionOp &partitionOp) {
15821591
return SILIsolationInfo::get(partitionOp.getSourceInst());
15831592
}

test/Concurrency/transfernonsendable_sending_params.swift

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
// MARK: Declarations //
88
////////////////////////
99

10-
class NonSendableKlass {}
10+
class NonSendableKlass {
11+
func use() {}
12+
}
1113

1214
struct NonSendableStruct {
1315
var first = NonSendableKlass()
@@ -55,6 +57,9 @@ func throwingFunction() throws { fatalError() }
5557
func transferArg(_ x: sending NonSendableKlass) {
5658
}
5759

60+
func transferArgAsync(_ x: sending NonSendableKlass) async {
61+
}
62+
5863
func transferArgWithOtherParam(_ x: sending NonSendableKlass, _ y: NonSendableKlass) {
5964
}
6065

@@ -559,3 +564,56 @@ extension MyActor {
559564
}
560565
}
561566
}
567+
568+
// We would normally not error here since transferArg is nonisolated and c is
569+
// disconnected. Since c is passed as sending, we shouldn't squelch this.
570+
func disconnectedPassedSendingToNonIsolatedCallee(
571+
) async -> Void {
572+
let c = NonSendableKlass()
573+
transferArg(c) // expected-warning {{sending 'c' risks causing data races}}
574+
// expected-note @-1 {{'c' used after being passed as a 'sending' parameter}}
575+
c.use() // expected-note {{access can happen concurrently}}
576+
}
577+
578+
// We would normally not error here since transferArg is nonisolated and c is
579+
// disconnected. Since c is passed as sending, we shouldn't squelch this.
580+
func disconnectedPassedSendingToAsyncNonIsolatedCallee(
581+
) async -> Void {
582+
let c = NonSendableKlass()
583+
await transferArgAsync(c) // expected-warning {{sending 'c' risks causing data races}}
584+
// expected-note @-1 {{'c' used after being passed as a 'sending' parameter}}
585+
c.use() // expected-note {{access can happen concurrently}}
586+
}
587+
588+
// We would normally not error here since transferArg is nonisolated and c is
589+
// disconnected. Since c is passed as sending, we shouldn't squelch this.
590+
func disconnectedPassedSendingToNonIsolatedCalleeIsolatedParam2(
591+
isolation: isolated (any Actor)? = nil
592+
) async -> Void {
593+
let c = NonSendableKlass()
594+
transferArg(c) // expected-warning {{sending 'c' risks causing data races}}
595+
// expected-note @-1 {{'c' used after being passed as a 'sending' parameter}}
596+
c.use() // expected-note {{access can happen concurrently}}
597+
}
598+
599+
// We would normally not error here since transferArg is nonisolated and c is
600+
// disconnected. Since c is passed as sending, we shouldn't squelch this.
601+
func disconnectedPassedSendingToAsyncNonIsolatedCalleeIsolatedParam2(
602+
isolation: isolated (any Actor)? = nil
603+
) async -> Void {
604+
let c = NonSendableKlass()
605+
await transferArgAsync(c) // expected-warning {{sending 'c' risks causing data races}}
606+
// expected-note @-1 {{'c' used after being passed as a 'sending' parameter}}
607+
c.use() // expected-note {{access can happen concurrently}}
608+
}
609+
610+
// We would normally not error here since transferArg is nonisolated and c is
611+
// disconnected. Since c is passed as sending, we shouldn't squelch this.
612+
func disconnectedPassedSendingToNonIsolatedCalleeIsolatedParam3(
613+
isolation: isolated (any Actor)? = nil
614+
) -> Void {
615+
let c = NonSendableKlass()
616+
transferArg(c) // expected-warning {{sending 'c' risks causing data races}}
617+
// expected-note @-1 {{'c' used after being passed as a 'sending' parameter}}
618+
c.use() // expected-note {{access can happen concurrently}}
619+
}

unittests/SILOptimizer/PartitionUtilsTest.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ struct MockedPartitionOpEvaluator final
6262
return {};
6363
}
6464

65+
static SILInstruction *getSourceInst(const PartitionOp &partitionOp) {
66+
return nullptr;
67+
}
68+
6569
static bool doesFunctionHaveSendingResult(const PartitionOp &partitionOp) {
6670
return false;
6771
}
@@ -107,6 +111,10 @@ struct MockedPartitionOpEvaluatorWithFailureCallback final
107111
static SILIsolationInfo getIsolationInfo(const PartitionOp &partitionOp) {
108112
return {};
109113
}
114+
115+
static SILInstruction *getSourceInst(const PartitionOp &partitionOp) {
116+
return nullptr;
117+
}
110118
};
111119

112120
} // namespace

0 commit comments

Comments
 (0)