Skip to content

Commit 2159c0c

Browse files
committed
[Concurrency] Diagnose Sendable violations in captures of local functions.
1 parent 2e9c64d commit 2159c0c

File tree

3 files changed

+30
-8
lines changed

3 files changed

+30
-8
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5236,8 +5236,9 @@ ERROR(concurrent_access_of_inout_param,none,
52365236
"concurrently-executing code",
52375237
(DeclName))
52385238
ERROR(non_sendable_capture,none,
5239-
"capture of %1 with non-sendable type %0 in a `@Sendable` closure",
5240-
(Type, DeclName))
5239+
"capture of %1 with non-sendable type %0 in a `@Sendable` "
5240+
"%select{local function|closure}2",
5241+
(Type, DeclName, bool))
52415242
ERROR(implicit_async_let_non_sendable_capture,none,
52425243
"capture of %1 with non-sendable type %0 in 'async let' binding",
52435244
(Type, DeclName))

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2118,9 +2118,9 @@ namespace {
21182118
}
21192119

21202120
/// Check closure captures for Sendable violations.
2121-
void checkClosureCaptures(AbstractClosureExpr *closure) {
2121+
void checkLocalCaptures(AnyFunctionRef localFunc) {
21222122
SmallVector<CapturedValue, 2> captures;
2123-
closure->getCaptureInfo().getLocalCaptures(captures);
2123+
localFunc.getCaptureInfo().getLocalCaptures(captures);
21242124
for (const auto &capture : captures) {
21252125
if (capture.isDynamicSelfMetadata())
21262126
continue;
@@ -2130,14 +2130,19 @@ namespace {
21302130
// If the closure won't execute concurrently with the context in
21312131
// which the declaration occurred, it's okay.
21322132
auto decl = capture.getDecl();
2133-
if (!mayExecuteConcurrentlyWith(closure, decl->getDeclContext()))
2133+
auto *context = localFunc.getAsDeclContext();
2134+
if (!mayExecuteConcurrentlyWith(context, decl->getDeclContext()))
21342135
continue;
21352136

21362137
Type type = getDeclContext()
21372138
->mapTypeIntoContext(decl->getInterfaceType())
21382139
->getReferenceStorageReferent();
21392140

2140-
if (closure->isImplicit()) {
2141+
if (type->hasError())
2142+
continue;
2143+
2144+
auto *closure = localFunc.getAbstractClosureExpr();
2145+
if (closure && closure->isImplicit()) {
21412146
auto *patternBindingDecl = getTopPatternBindingDecl();
21422147
if (patternBindingDecl && patternBindingDecl->isAsyncLet()) {
21432148
diagnoseNonSendableTypes(
@@ -2152,7 +2157,8 @@ namespace {
21522157
}
21532158
} else {
21542159
diagnoseNonSendableTypes(type, getDeclContext(), capture.getLoc(),
2155-
diag::non_sendable_capture, decl->getName());
2160+
diag::non_sendable_capture, decl->getName(),
2161+
/*closure=*/closure != nullptr);
21562162
}
21572163
}
21582164
}
@@ -2220,6 +2226,10 @@ namespace {
22202226

22212227
PreWalkAction walkToDeclPre(Decl *decl) override {
22222228
if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
2229+
if (func->isLocalContext()) {
2230+
checkLocalCaptures(func);
2231+
}
2232+
22232233
contextStack.push_back(func);
22242234
}
22252235

@@ -2254,7 +2264,7 @@ namespace {
22542264

22552265
if (auto *closure = dyn_cast<AbstractClosureExpr>(expr)) {
22562266
closure->setActorIsolation(determineClosureIsolation(closure));
2257-
checkClosureCaptures(closure);
2267+
checkLocalCaptures(closure);
22582268
contextStack.push_back(closure);
22592269
return Action::Continue(expr);
22602270
}

test/Concurrency/sendable_checking.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ final class NonSendable {
250250
// expected-note @-1 3 {{class 'NonSendable' does not conform to the 'Sendable' protocol}}
251251
// SendNonSendable emits 3 fewer errors here.
252252
// expected-targeted-and-complete-note @-3 5 {{class 'NonSendable' does not conform to the 'Sendable' protocol}}
253+
// expected-complete-and-sns-note @-4 {{class 'NonSendable' does not conform to the 'Sendable' protocol}}
253254
var value = ""
254255

255256
@MainActor
@@ -305,3 +306,13 @@ func callNonisolatedAsyncClosure(
305306
await f(ns)
306307
// expected-targeted-and-complete-warning@-1 {{passing argument of non-sendable type 'NonSendable' outside of main actor-isolated context may introduce data races}}
307308
}
309+
310+
@available(SwiftStdlib 5.1, *)
311+
func testLocalCaptures() {
312+
let ns = NonSendable()
313+
314+
@Sendable func a2() -> NonSendable {
315+
return ns
316+
// expected-complete-and-sns-warning@-1 {{capture of 'ns' with non-sendable type 'NonSendable' in a `@Sendable` local function}}
317+
}
318+
}

0 commit comments

Comments
 (0)