Skip to content

Commit 260ade8

Browse files
committed
[Unsafe] Teach for..in loops to let the sequence's 'unsafe' cover next()
Warnings about unsafe uses due to an @unsafe IteratorProtocol conformance (for the implicit call to next()) could not be silenced. Follow the same path we did for the Sequence conformance (and makeIterator() call) by associating it with the `unsafe` on the sequence argument. This isn't the only solution here, but it's a reasonable one.
1 parent 62f128f commit 260ade8

File tree

3 files changed

+24
-0
lines changed

3 files changed

+24
-0
lines changed

lib/Sema/CSGen.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3854,6 +3854,12 @@ generateForEachStmtConstraints(ConstraintSystem &cs, DeclContext *dc,
38543854
AwaitExpr::createImplicit(ctx, nextCall->getLoc(), nextCall);
38553855
}
38563856

3857+
// Wrap the 'next' call in 'unsafe', if there is one.
3858+
if (unsafeExpr) {
3859+
nextCall = new (ctx) UnsafeExpr(unsafeExpr->getLoc(), nextCall, Type(),
3860+
/*implicit=*/true);
3861+
}
3862+
38573863
// The iterator type must conform to IteratorProtocol.
38583864
{
38593865
ProtocolDecl *iteratorProto = TypeChecker::getProtocol(

lib/Sema/TypeCheckEffects.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4122,6 +4122,12 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
41224122

41234123
if (auto parsedSequence = S->getParsedSequence()) {
41244124
parentMap[typeCheckedExpr] = parsedSequence;
4125+
4126+
if (auto nextCall = S->getNextCall()) {
4127+
auto nextParentMap = nextCall->getParentMap();
4128+
parentMap.insert(nextParentMap.begin(), nextParentMap.end());
4129+
parentMap[nextCall] = parsedSequence;
4130+
}
41254131
}
41264132
}
41274133

test/Unsafe/unsafe-suppression.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,15 @@ var yieldUnsafeOkay: Int {
143143
yield unsafe &x
144144
}
145145
}
146+
147+
struct UnsafeSequence: @unsafe IteratorProtocol, @unsafe Sequence {
148+
@unsafe func next() -> Int? { nil }
149+
}
150+
151+
func forEachLoop(us: UnsafeSequence) {
152+
for _ in us { } // expected-warning{{expression uses unsafe constructs but is not marked with 'unsafe' [Unsafe]}}{{12-12=unsafe }}
153+
// expected-note@-1{{@unsafe conformance of 'UnsafeSequence' to protocol 'Sequence' involves unsafe code}}
154+
// expected-note@-2{{reference to unsafe instance method 'next()'}}
155+
156+
for _ in unsafe us { }
157+
}

0 commit comments

Comments
 (0)