Skip to content

Commit 59e1474

Browse files
authored
Merge pull request #85164 from gottesmm/pr-39de26ee629693f844665c42d2bdff56838838a0
[rbi] When translating a Store, make sure to require src even if the value being stored is Sendable
2 parents aad6cae + f0a4571 commit 59e1474

File tree

4 files changed

+73
-2
lines changed

4 files changed

+73
-2
lines changed

lib/SILOptimizer/Analysis/RegionAnalysis.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2982,7 +2982,7 @@ class PartitionOpTranslator {
29822982
/// dest to src. If the \p dest could be aliased, then we must instead treat
29832983
/// them as merges, to ensure any aliases of \p dest are also updated.
29842984
void translateSILStore(Operand *dest, Operand *src,
2985-
SILIsolationInfo resultIsolationInfoOverride = {}) {
2985+
SILIsolationInfo resultIsolationInfoOverride = {}) {
29862986
SILValue destValue = dest->get();
29872987

29882988
if (auto destResult = tryToTrackValue(destValue)) {
@@ -3010,7 +3010,14 @@ class PartitionOpTranslator {
30103010
resultIsolationInfoOverride);
30113011
}
30123012

3013-
// Stores to storage of non-Sendable type can be ignored.
3013+
// If we reached this point, our destination is something that is Sendable
3014+
// and is not an address that comes from a non-Sendable base... so we can
3015+
// ignore the store part. But we still need tosee if our src (which also
3016+
// must be Sendable) comes from a non-Sendable base. In such a case, we need
3017+
// to require that.
3018+
if (auto srcResult = tryToTrackValue(src->get())) {
3019+
builder.addRequire(*srcResult);
3020+
}
30143021
}
30153022

30163023
void translateSILTupleAddrConstructor(TupleAddrConstructorInst *inst) {

lib/SILOptimizer/Utils/SILIsolationInfo.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -965,6 +965,19 @@ SILIsolationInfo SILIsolationInfo::get(SILInstruction *inst) {
965965
}
966966
}
967967

968+
if (auto *bbi = dyn_cast<BeginBorrowInst>(inst)) {
969+
if (bbi->isFromVarDecl()) {
970+
// See if we have the actual AST information on our instruction.
971+
if (auto *varDecl = bbi->getLoc().getAsASTNode<VarDecl>()) {
972+
auto isolation = swift::getActorIsolation(varDecl);
973+
if (isolation.getKind() == ActorIsolation::NonisolatedUnsafe) {
974+
return SILIsolationInfo::getDisconnected(
975+
true /*is nonisolated(unsafe)*/);
976+
}
977+
}
978+
}
979+
}
980+
968981
/// Consider non-Sendable metatypes to be task-isolated, so they cannot cross
969982
/// into another isolation domain.
970983
if (auto *mi = dyn_cast<MetatypeInst>(inst)) {

test/Concurrency/transfernonsendable.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2025,3 +2025,42 @@ func avoidThinkingClosureParameterIsSending() {
20252025
}
20262026
}
20272027
}
2028+
2029+
enum RequireSrcWhenStoringEvenWhenSendable {
2030+
func test<T: Sendable>(t: T) {
2031+
var result: T = t
2032+
Task { // expected-ni-warning {{sending value of non-Sendable type '() async -> ()' risks causing data races}}
2033+
// expected-ni-note @-1 {{Passing value of non-Sendable type '() async -> ()' as a 'sending' argument to initializer 'init(name:priority:operation:)' risks causing races in between local and caller code}}
2034+
// expected-ni-ns-warning @-2 {{sending value of non-Sendable type '@concurrent () async -> ()' risks causing data races}}
2035+
// expected-ni-ns-note @-3 {{Passing value of non-Sendable type '@concurrent () async -> ()' as a 'sending' argument to initializer 'init(name:priority:operation:)' risks causing races in between local and caller code}}
2036+
result = t
2037+
}
2038+
useValue(result) // expected-note {{access can happen concurrently}}
2039+
}
2040+
2041+
func test2() {
2042+
var result: Any = 0
2043+
Task { // expected-ni-warning {{sending value of non-Sendable type '() async -> ()' risks causing data races}}
2044+
// expected-ni-note @-1 {{Passing value of non-Sendable type '() async -> ()' as a 'sending' argument to initializer 'init(name:priority:operation:)' risks causing races in between local and caller code}}
2045+
// expected-ni-ns-warning @-2 {{sending value of non-Sendable type '@concurrent () async -> ()' risks causing data races}}
2046+
// expected-ni-ns-note @-3 {{Passing value of non-Sendable type '@concurrent () async -> ()' as a 'sending' argument to initializer 'init(name:priority:operation:)' risks causing races in between local and caller code}}
2047+
result = 0
2048+
}
2049+
useValue(result) // expected-note {{access can happen concurrently}}
2050+
}
2051+
2052+
protocol Initializable {
2053+
init()
2054+
}
2055+
2056+
func test3<T: Initializable & SendableMetatype>(type: T.Type) {
2057+
var result = type.init()
2058+
Task { // expected-ni-warning {{sending value of non-Sendable type '() async -> ()' risks causing data races}}
2059+
// expected-ni-note @-1 {{Passing value of non-Sendable type '() async -> ()' as a 'sending' argument to initializer 'init(name:priority:operation:)' risks causing races in between local and caller code}}
2060+
// expected-ni-ns-warning @-2 {{sending value of non-Sendable type '@concurrent () async -> ()' risks causing data races}}
2061+
// expected-ni-ns-note @-3 {{Passing value of non-Sendable type '@concurrent () async -> ()' as a 'sending' argument to initializer 'init(name:priority:operation:)' risks causing races in between local and caller code}}
2062+
result = type.init()
2063+
}
2064+
useValue(result) // expected-note {{access can happen concurrently}}
2065+
}
2066+
}

test/Concurrency/transfernonsendable_nonisolatedunsafe.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,18 @@ func useAfterTransferLetSquelchedIndirectAddressOnly<T : ProvidesStaticValue>(_
329329
print(ns4)
330330
}
331331

332+
func testNonisolatedUnsafeForwardDeclaredVar<T: Sendable>(_ body: @escaping @Sendable () async throws -> T) throws -> T {
333+
nonisolated(unsafe) var result: Result<T, Error>!
334+
Task {
335+
do {
336+
result = .success(try await body())
337+
} catch {
338+
result = .failure(error)
339+
}
340+
}
341+
return try result.get()
342+
}
343+
332344
////////////////////////
333345
// MARK: Global Tests //
334346
////////////////////////

0 commit comments

Comments
 (0)