Skip to content

Commit 7303124

Browse files
committed
Effects: Treat #selector as covering throws/async effects in its operand
Fixes rdar://151968656
1 parent 5382e12 commit 7303124

File tree

2 files changed

+46
-0
lines changed

2 files changed

+46
-0
lines changed

lib/Sema/TypeCheckEffects.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,8 @@ class EffectsHandlingWalker : public ASTWalker {
713713
}
714714
} else if (auto TE = dyn_cast<MakeTemporarilyEscapableExpr>(E)) {
715715
recurse = asImpl().checkTemporarilyEscapable(TE);
716+
} else if (auto OSE = dyn_cast<ObjCSelectorExpr>(E)) {
717+
recurse = asImpl().checkObjCSelector(OSE);
716718
}
717719

718720
// Error handling validation (via checkTopLevelEffects) happens after
@@ -2269,6 +2271,10 @@ class ApplyClassifier {
22692271
return ShouldRecurse;
22702272
}
22712273

2274+
ShouldRecurse_t checkObjCSelector(ObjCSelectorExpr *E) {
2275+
return ShouldNotRecurse;
2276+
}
2277+
22722278
ConditionalEffectKind checkExhaustiveDoBody(DoCatchStmt *S) {
22732279
// All errors thrown by the do body are caught, but any errors thrown
22742280
// by the catch bodies are bounded by the throwing kind of the do body.
@@ -2418,6 +2424,10 @@ class ApplyClassifier {
24182424
return ShouldRecurse;
24192425
}
24202426

2427+
ShouldRecurse_t checkObjCSelector(ObjCSelectorExpr *E) {
2428+
return ShouldNotRecurse;
2429+
}
2430+
24212431
void visitExprPre(Expr *expr) { return; }
24222432
};
24232433

@@ -2535,6 +2545,10 @@ class ApplyClassifier {
25352545
return ShouldRecurse;
25362546
}
25372547

2548+
ShouldRecurse_t checkObjCSelector(ObjCSelectorExpr *E) {
2549+
return ShouldNotRecurse;
2550+
}
2551+
25382552
void visitExprPre(Expr *expr) { return; }
25392553
};
25402554

@@ -3716,6 +3730,12 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
37163730
Self.Flags.set(ContextFlags::InAsyncLet);
37173731
}
37183732

3733+
/// Enter a subexpression that's never exected.
3734+
void enterNonExecuting() {
3735+
Self.Flags.set(ContextFlags::IsTryCovered);
3736+
Self.Flags.set(ContextFlags::IsAsyncCovered);
3737+
}
3738+
37193739
void refineLocalContext(Context newContext) {
37203740
Self.CurContext = newContext;
37213741
}
@@ -3825,6 +3845,13 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
38253845
OldMaxThrowingKind = std::max(OldMaxThrowingKind, Self.MaxThrowingKind);
38263846
}
38273847

3848+
void preserveCoverageFromNonExecutingOperand() {
3849+
OldFlags.mergeFrom(ContextFlags::asyncAwaitFlags(), Self.Flags);
3850+
OldFlags.mergeFrom(ContextFlags::throwFlags(), Self.Flags);
3851+
OldFlags.mergeFrom(ContextFlags::unsafeFlags(), Self.Flags);
3852+
OldMaxThrowingKind = std::max(OldMaxThrowingKind, Self.MaxThrowingKind);
3853+
}
3854+
38283855
void preserveCoverageFromOptionalOrForcedTryOperand() {
38293856
OldFlags.mergeFrom(ContextFlags::asyncAwaitFlags(), Self.Flags);
38303857
OldFlags.mergeFrom(ContextFlags::unsafeFlags(), Self.Flags);
@@ -4026,6 +4053,17 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
40264053
return ShouldRecurse;
40274054
}
40284055

4056+
ShouldRecurse_t checkObjCSelector(ObjCSelectorExpr *E) {
4057+
// Walk the operand.
4058+
ContextScope scope(*this, std::nullopt);
4059+
scope.enterNonExecuting();
4060+
4061+
E->getSubExpr()->walk(*this);
4062+
4063+
scope.preserveCoverageFromNonExecutingOperand();
4064+
return ShouldNotRecurse;
4065+
}
4066+
40294067
ConditionalEffectKind checkExhaustiveDoBody(DoCatchStmt *S) {
40304068
// This is a context where errors are handled.
40314069
ContextScope scope(*this, CurContext.withHandlesErrors());

test/expr/primary/selector/selector.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,11 @@ extension SomeProtocol {
172172
func test() -> Selector {
173173
#selector(OverloadedFuncAndProperty.f)
174174
}
175+
176+
@objc protocol HasThrows {
177+
@objc optional func doSomething(to object: AnyObject) throws -> Void
178+
}
179+
180+
func testWithThrowing(obj: AnyObject) {
181+
_ = #selector(HasThrows.doSomething(to:))
182+
}

0 commit comments

Comments
 (0)