diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index b94d96491b54c..ed935427b53f6 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -3854,6 +3854,12 @@ generateForEachStmtConstraints(ConstraintSystem &cs, DeclContext *dc, AwaitExpr::createImplicit(ctx, nextCall->getLoc(), nextCall); } + // Wrap the 'next' call in 'unsafe', if there is one. + if (unsafeExpr) { + nextCall = new (ctx) UnsafeExpr(unsafeExpr->getLoc(), nextCall, Type(), + /*implicit=*/true); + } + // The iterator type must conform to IteratorProtocol. { ProtocolDecl *iteratorProto = TypeChecker::getProtocol( diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp index 88b1c55d6770e..ff1f670635b86 100644 --- a/lib/Sema/TypeCheckEffects.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -4122,6 +4122,12 @@ class CheckEffectsCoverage : public EffectsHandlingWalker if (auto parsedSequence = S->getParsedSequence()) { parentMap[typeCheckedExpr] = parsedSequence; + + if (auto nextCall = S->getNextCall()) { + auto nextParentMap = nextCall->getParentMap(); + parentMap.insert(nextParentMap.begin(), nextParentMap.end()); + parentMap[nextCall] = parsedSequence; + } } } diff --git a/test/Unsafe/safe.swift b/test/Unsafe/safe.swift index 26ff07135358b..31bca73c797ca 100644 --- a/test/Unsafe/safe.swift +++ b/test/Unsafe/safe.swift @@ -87,8 +87,9 @@ func returnsExistentialP() -> any P { // expected-note@-1{{@unsafe conformance of 'Int' to protocol 'P' involves unsafe code}} } -struct UnsafeAsSequence: @unsafe Sequence, IteratorProtocol { - mutating func next() -> Int? { nil } +// FIXME: Should work even if the IteratorProtocol conformance is safe +struct UnsafeAsSequence: @unsafe Sequence, @unsafe IteratorProtocol { + @unsafe mutating func next() -> Int? { nil } } func testUnsafeAsSequenceForEach() { @@ -96,6 +97,7 @@ func testUnsafeAsSequenceForEach() { // expected-warning@+1{{expression uses unsafe constructs but is not marked with 'unsafe'}}{{12-12=unsafe }} for _ in uas { } // expected-note{{conformance}} + // expected-note@-1{{reference}} for _ in unsafe uas { } // okay } diff --git a/test/Unsafe/unsafe-suppression.swift b/test/Unsafe/unsafe-suppression.swift index fc0983b0a0565..57e049aaed36c 100644 --- a/test/Unsafe/unsafe-suppression.swift +++ b/test/Unsafe/unsafe-suppression.swift @@ -143,3 +143,15 @@ var yieldUnsafeOkay: Int { yield unsafe &x } } + +struct UnsafeSequence: @unsafe IteratorProtocol, @unsafe Sequence { + @unsafe func next() -> Int? { nil } +} + +func forEachLoop(us: UnsafeSequence) { + for _ in us { } // expected-warning{{expression uses unsafe constructs but is not marked with 'unsafe' [Unsafe]}}{{12-12=unsafe }} + // expected-note@-1{{@unsafe conformance of 'UnsafeSequence' to protocol 'Sequence' involves unsafe code}} + // expected-note@-2{{reference to unsafe instance method 'next()'}} + + for _ in unsafe us { } +}