Skip to content

Commit 3542b1d

Browse files
authored
Merge pull request #82938 from DougGregor/unsafe-for-in-fixes
2 parents fd7dd78 + 35628cb commit 3542b1d

File tree

4 files changed

+23
-10
lines changed

4 files changed

+23
-10
lines changed

lib/Sema/CSGen.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4729,10 +4729,15 @@ generateForEachStmtConstraints(ConstraintSystem &cs, DeclContext *dc,
47294729
}
47304730

47314731
// Wrap the 'next' call in 'unsafe', if the for..in loop has that
4732-
// effect.
4733-
if (stmt->getUnsafeLoc().isValid()) {
4734-
nextCall = new (ctx) UnsafeExpr(
4735-
stmt->getUnsafeLoc(), nextCall, Type(), /*implicit=*/true);
4732+
// effect or if the loop is async (in which case the iterator variable
4733+
// is nonisolated(unsafe).
4734+
if (stmt->getUnsafeLoc().isValid() ||
4735+
(isAsync &&
4736+
ctx.LangOpts.StrictConcurrencyLevel == StrictConcurrency::Complete)) {
4737+
SourceLoc loc = stmt->getUnsafeLoc();
4738+
if (loc.isInvalid())
4739+
loc = stmt->getForLoc();
4740+
nextCall = new (ctx) UnsafeExpr(loc, nextCall, Type(), /*implicit=*/true);
47364741
}
47374742

47384743
// The iterator type must conform to IteratorProtocol.

lib/Sema/TypeCheckEffects.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2457,7 +2457,7 @@ class ApplyClassifier {
24572457
return ShouldRecurse;
24582458
}
24592459
ShouldRecurse_t checkUnsafe(UnsafeExpr *E) {
2460-
return E->isImplicit() ? ShouldRecurse : ShouldNotRecurse;
2460+
return ShouldNotRecurse;
24612461
}
24622462
ShouldRecurse_t checkTry(TryExpr *E) {
24632463
return ShouldRecurse;
@@ -4626,10 +4626,6 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
46264626
diagnoseUnsafeUse(unsafeUse);
46274627
}
46284628
}
4629-
} else if (S->getUnsafeLoc().isValid()) {
4630-
// Extraneous "unsafe" on the sequence.
4631-
Ctx.Diags.diagnose(S->getUnsafeLoc(), diag::no_unsafe_in_unsafe_for)
4632-
.fixItRemove(S->getUnsafeLoc());
46334629
}
46344630

46354631
return ShouldRecurse;
@@ -4689,7 +4685,10 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
46894685
return;
46904686
}
46914687

4692-
Ctx.Diags.diagnose(E->getUnsafeLoc(), diag::no_unsafe_in_unsafe)
4688+
Ctx.Diags.diagnose(E->getUnsafeLoc(),
4689+
forEachNextCallExprs.contains(E)
4690+
? diag::no_unsafe_in_unsafe_for
4691+
: diag::no_unsafe_in_unsafe)
46934692
.fixItRemove(E->getUnsafeLoc());
46944693
}
46954694

test/Unsafe/safe.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ func testUnsafeAsSequenceForEach() {
9898
for _ in unsafe uas { } // expected-warning{{for-in loop uses unsafe constructs but is not marked with 'unsafe'}}{{documentation-file=strict-memory-safety}}{{7-7=unsafe }}
9999

100100
for unsafe _ in unsafe uas { } // okay
101+
102+
for unsafe _ in [1, 2, 3] { } // expected-warning{{no unsafe operations occur within 'unsafe' for-in loop}}
101103
}
102104

103105
func testForInUnsafeAmbiguity(_ integers: [Int]) {

test/Unsafe/unsafe_concurrency.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,10 @@ open class SyntaxVisitor {
5555
open class SyntaxAnyVisitor: SyntaxVisitor {
5656
override open func visit(_ token: TokenSyntax) { }
5757
}
58+
59+
@available(SwiftStdlib 5.1, *)
60+
func testMemorySafetyWithForLoop() async {
61+
let (stream, continuation) = AsyncStream<Int>.makeStream()
62+
for await _ in stream {}
63+
_ = continuation
64+
}

0 commit comments

Comments
 (0)