Skip to content

Commit 76ae065

Browse files
committed
[Concurrency] Suppress Sendable argument diagnostics for values that come
from `nonisolated(unsafe)` declarations.
1 parent b54cfc4 commit 76ae065

File tree

4 files changed

+40
-4
lines changed

4 files changed

+40
-4
lines changed

include/swift/AST/Expr.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,10 @@ class alignas(8) Expr : public ASTAllocated<Expr> {
448448
return const_cast<Expr *>(this)->getValueProvidingExpr();
449449
}
450450

451+
/// Find the original expression value, looking through various
452+
/// implicit conversions.
453+
const Expr *findOriginalValue() const;
454+
451455
/// Find the original type of a value, looking through various implicit
452456
/// conversions.
453457
Type findOriginalType() const;

lib/AST/Expr.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2875,7 +2875,7 @@ FrontendStatsTracer::getTraceFormatter<const Expr *>() {
28752875
return &TF;
28762876
}
28772877

2878-
Type Expr::findOriginalType() const {
2878+
const Expr *Expr::findOriginalValue() const {
28792879
auto *expr = this;
28802880
do {
28812881
expr = expr->getSemanticsProvidingExpr();
@@ -2898,6 +2898,11 @@ Type Expr::findOriginalType() const {
28982898
break;
28992899
} while (true);
29002900

2901+
return expr;
2902+
}
2903+
2904+
Type Expr::findOriginalType() const {
2905+
auto *expr = findOriginalValue();
29012906
return expr->getType()->getRValueType();
29022907
}
29032908

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1923,6 +1923,15 @@ static FuncDecl *findAnnotatableFunction(DeclContext *dc) {
19231923
return fn;
19241924
}
19251925

1926+
static bool shouldCheckSendable(Expr *expr) {
1927+
if (auto *declRef = dyn_cast<DeclRefExpr>(expr->findOriginalValue())) {
1928+
auto isolation = getActorIsolation(declRef->getDecl());
1929+
return isolation != ActorIsolation::NonisolatedUnsafe;
1930+
}
1931+
1932+
return true;
1933+
}
1934+
19261935
bool swift::diagnoseApplyArgSendability(ApplyExpr *apply, const DeclContext *declContext) {
19271936
auto isolationCrossing = apply->getIsolationCrossing();
19281937
if (!isolationCrossing.has_value())
@@ -1935,7 +1944,9 @@ bool swift::diagnoseApplyArgSendability(ApplyExpr *apply, const DeclContext *dec
19351944
// Check the 'self' argument.
19361945
if (auto *selfApply = dyn_cast<SelfApplyExpr>(apply->getFn())) {
19371946
auto *base = selfApply->getBase();
1938-
if (diagnoseNonSendableTypes(
1947+
1948+
if (shouldCheckSendable(base) &&
1949+
diagnoseNonSendableTypes(
19391950
base->getType(),
19401951
declContext, base->getStartLoc(),
19411952
diag::non_sendable_call_argument,
@@ -1954,6 +1965,7 @@ bool swift::diagnoseApplyArgSendability(ApplyExpr *apply, const DeclContext *dec
19541965
// Dig out the location of the argument.
19551966
SourceLoc argLoc = apply->getLoc();
19561967
Type argType;
1968+
bool checkSendable = true;
19571969
if (auto argList = apply->getArgs()) {
19581970
auto arg = argList->get(paramIdx);
19591971
if (arg.getStartLoc().isValid())
@@ -1962,6 +1974,7 @@ bool swift::diagnoseApplyArgSendability(ApplyExpr *apply, const DeclContext *dec
19621974
// Determine the type of the argument, ignoring any implicit
19631975
// conversions that could have stripped sendability.
19641976
if (Expr *argExpr = arg.getExpr()) {
1977+
checkSendable = shouldCheckSendable(argExpr);
19651978
argType = argExpr->findOriginalType();
19661979

19671980
// If this is a default argument expression, don't check Sendability
@@ -1976,7 +1989,8 @@ bool swift::diagnoseApplyArgSendability(ApplyExpr *apply, const DeclContext *dec
19761989
}
19771990
}
19781991

1979-
if (diagnoseNonSendableTypes(
1992+
if (checkSendable &&
1993+
diagnoseNonSendableTypes(
19801994
argType ? argType : param.getParameterType(),
19811995
declContext, argLoc, diag::non_sendable_call_argument,
19821996
isolationCrossing.value().exitsIsolation(),

test/Concurrency/experimental_feature_strictconcurrency.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %target-swift-frontend -disable-availability-checking -parse-as-library -enable-experimental-feature StrictConcurrency -enable-experimental-feature GlobalConcurrency -emit-sil -o /dev/null -verify %s
22
// RUN: %target-swift-frontend -disable-availability-checking -parse-as-library -enable-experimental-feature StrictConcurrency=complete -enable-experimental-feature GlobalConcurrency -emit-sil -o /dev/null -verify %s
3-
// RUN: %target-swift-frontend -disable-availability-checking -parse-as-library -enable-experimental-feature StrictConcurrency=complete -enable-experimental-feature GlobalConcurrency -emit-sil -o /dev/null -verify -enable-experimental-feature RegionBasedIsolation %s
3+
// RUN: %target-swift-frontend -disable-availability-checking -parse-as-library -enable-experimental-feature StrictConcurrency=complete -enable-experimental-feature GlobalConcurrency -emit-sil -o /dev/null -verify -verify-additional-prefix region-isolation- -enable-experimental-feature RegionBasedIsolation %s
44

55
// REQUIRES: concurrency
66
// REQUIRES: asserts
@@ -84,3 +84,16 @@ func testLocalNonisolatedUnsafe() async {
8484
}
8585
print(await task.value)
8686
}
87+
88+
@MainActor
89+
func iterate(stream: AsyncStream<Int>) async {
90+
nonisolated(unsafe) var it = stream.makeAsyncIterator()
91+
// FIXME: Region isolation should consider a value from a 'nonisolated(unsafe)'
92+
// declaration to be in a disconnected region
93+
94+
// expected-region-isolation-warning@+2 {{passing argument of non-sendable type 'AsyncStream<Int>.Iterator' from main actor-isolated context to nonisolated context at this call site could yield a race with accesses later in this function}}
95+
// expected-region-isolation-note@+1 {{access here could race}}
96+
while let element = await it.next() {
97+
print(element)
98+
}
99+
}

0 commit comments

Comments
 (0)