Skip to content

Commit eb57309

Browse files
committed
[region-isolation] Teach the checker that a use of a local value after being strongly transferred is an error.
Before the previous patch, we were just getting lucky on macOS due to UB. Now that the UB is fixed, we correctly crash without this commit since we were not pattern matching the simple case of a local value that was transferred and used later.
1 parent 23adcba commit eb57309

File tree

3 files changed

+55
-17
lines changed

3 files changed

+55
-17
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -901,6 +901,9 @@ WARNING(regionbasedisolation_transfer_yields_race_with_isolation, none,
901901
WARNING(regionbasedisolation_transfer_yields_race_transferring_parameter, none,
902902
"transferred value of non-Sendable type %0 into transferring parameter; later accesses could result in races",
903903
(Type))
904+
WARNING(regionbasedisolation_transfer_yields_race_stronglytransferred_binding, none,
905+
"binding of non-Sendable type %0 accessed after being transferred; later accesses could result in races",
906+
(Type))
904907
NOTE(regionbasedisolation_maybe_race, none,
905908
"access here could race", ())
906909
ERROR(regionbasedisolation_unknown_pattern, none,

lib/SILOptimizer/Mandatory/TransferNonSendable.cpp

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ enum class UseDiagnosticInfoKind {
101101
/// Used if the error is due to a transfer into an assignment into a
102102
/// transferring parameter.
103103
AssignmentIntoTransferringParameter = 3,
104+
105+
/// Set to true if this is a use of a normal value that was strongly
106+
/// transferred.
107+
UseOfStronglyTransferredValue = 4,
104108
};
105109

106110
class UseDiagnosticInfo {
@@ -124,11 +128,16 @@ class UseDiagnosticInfo {
124128
UseDiagnosticInfoKind::AssignmentIntoTransferringParameter, {});
125129
}
126130

131+
static UseDiagnosticInfo forUseOfStronglyTransferredValue() {
132+
return UseDiagnosticInfo(
133+
UseDiagnosticInfoKind::UseOfStronglyTransferredValue, {});
134+
}
135+
127136
UseDiagnosticInfoKind getKind() const { return kind; }
128137

129138
ApplyIsolationCrossing getIsolationCrossing() const {
130-
assert(isolationCrossing && "Isolation crossing must be non-null");
131-
return *isolationCrossing;
139+
// assert(isolationCrossing && "Isolation crossing must be non-null");
140+
return isolationCrossing.value();
132141
}
133142

134143
private:
@@ -156,8 +165,19 @@ struct InferredCallerArgumentTypeInfo {
156165

157166
void initForApply(const Operand *op, ApplyExpr *expr);
158167
void initForAutoclosure(const Operand *op, AutoClosureExpr *expr);
159-
void initForAssignmentToTransferringParameter(const Operand *op,
160-
TrackableValue trackedValue);
168+
169+
void initForAssignmentToTransferringParameter(const Operand *op) {
170+
applyUses.emplace_back(
171+
op->get()->getType().getASTType(),
172+
UseDiagnosticInfo::forAssignmentIntoTransferringParameter());
173+
}
174+
175+
void initForUseOfStronglyTransferredValue(const Operand *op) {
176+
applyUses.emplace_back(
177+
op->get()->getType().getASTType(),
178+
UseDiagnosticInfo::forUseOfStronglyTransferredValue());
179+
}
180+
161181
Expr *getFoundExprForSelf(ApplyExpr *sourceApply) {
162182
if (auto callExpr = dyn_cast<CallExpr>(sourceApply))
163183
if (auto calledExpr =
@@ -190,8 +210,7 @@ void InferredCallerArgumentTypeInfo::initForApply(
190210

191211
void InferredCallerArgumentTypeInfo::initForApply(const Operand *op,
192212
ApplyExpr *sourceApply) {
193-
auto isolationCrossing = sourceApply->getIsolationCrossing();
194-
assert(isolationCrossing);
213+
auto isolationCrossing = sourceApply->getIsolationCrossing().value();
195214

196215
// Grab out full apply site and see if we can find a better expr.
197216
SILInstruction *i = const_cast<SILInstruction *>(op->getUser());
@@ -217,7 +236,7 @@ void InferredCallerArgumentTypeInfo::initForApply(const Operand *op,
217236
foundExpr ? foundExpr->findOriginalType() : baseInferredType;
218237
applyUses.emplace_back(
219238
inferredArgType,
220-
UseDiagnosticInfo::forIsolationCrossing(*isolationCrossing));
239+
UseDiagnosticInfo::forIsolationCrossing(isolationCrossing));
221240
}
222241

223242
namespace {
@@ -307,13 +326,6 @@ static SILValue getDestOfStoreOrCopyAddr(Operand *op) {
307326
return SILValue();
308327
}
309328

310-
void InferredCallerArgumentTypeInfo::initForAssignmentToTransferringParameter(
311-
const Operand *op, TrackableValue trackedValue) {
312-
applyUses.emplace_back(
313-
op->get()->getType().getASTType(),
314-
UseDiagnosticInfo::forAssignmentIntoTransferringParameter());
315-
}
316-
317329
void InferredCallerArgumentTypeInfo::init(const Operand *op) {
318330
baseInferredType = op->get()->getType().getASTType();
319331
auto *nonConstOp = const_cast<Operand *>(op);
@@ -324,7 +336,15 @@ void InferredCallerArgumentTypeInfo::init(const Operand *op) {
324336
if (auto destValue = getDestOfStoreOrCopyAddr(nonConstOp)) {
325337
auto trackedValue = valueMap.getTrackableValue(destValue);
326338
if (trackedValue.isTransferringParameter()) {
327-
return initForAssignmentToTransferringParameter(op, trackedValue);
339+
return initForAssignmentToTransferringParameter(op);
340+
}
341+
}
342+
343+
// Otherwise, see if our operand's instruction is a transferring parameter.
344+
if (auto fas = FullApplySite::isa(nonConstOp->getUser())) {
345+
if (fas.getArgumentParameterInfo(*nonConstOp)
346+
.hasOption(SILParameterInfo::Transferring)) {
347+
return initForUseOfStronglyTransferredValue(op);
328348
}
329349
}
330350

@@ -721,6 +741,14 @@ static void emitDiagnostics(RegionAnalysisFunctionInfo *regionInfo) {
721741
info.first)
722742
.highlight(transferOp->get().getLoc().getSourceRange());
723743
break;
744+
case UseDiagnosticInfoKind::UseOfStronglyTransferredValue:
745+
diagnose(
746+
transferOp,
747+
diag::
748+
regionbasedisolation_transfer_yields_race_stronglytransferred_binding,
749+
info.first)
750+
.highlight(transferOp->get().getLoc().getSourceRange());
751+
break;
724752
case UseDiagnosticInfoKind::AssignmentIntoTransferringParameter:
725753
diagnose(
726754
transferOp,

test/Concurrency/transfernonsendable_strong_transferring.swift

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,16 @@ func transferArgWithOtherParam2(_ x: Klass, _ y: transferring Klass) {
3232
// MARK: Tests //
3333
/////////////////
3434

35-
func testSimpleTransfer() {
35+
func testSimpleTransferLet() {
3636
let k = Klass()
37-
transferArg(k) // expected-warning {{passing argument of non-sendable type 'Klass' from nonisolated context to nonisolated context at this call site could yield a race with accesses later in this function}}
37+
transferArg(k) // expected-warning {{binding of non-Sendable type 'Klass' accessed after being transferred; later accesses could result in races}}
38+
useValue(k) // expected-note {{access here could race}}
39+
}
40+
41+
func testSimpleTransferVar() {
42+
var k = Klass()
43+
k = Klass()
44+
transferArg(k) // expected-warning {{binding of non-Sendable type 'Klass' accessed after being transferred; later accesses could result in races}}
3845
useValue(k) // expected-note {{access here could race}}
3946
}
4047

0 commit comments

Comments
 (0)