Skip to content

Commit 31fe75b

Browse files
authored
Merge pull request #81853 from DougGregor/objc-selector-effects
Effects: Treat #selector as covering throws/async effects in its operand
2 parents 284c371 + 7303124 commit 31fe75b

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
@@ -712,6 +712,8 @@ class EffectsHandlingWalker : public ASTWalker {
712712
}
713713
} else if (auto TE = dyn_cast<MakeTemporarilyEscapableExpr>(E)) {
714714
recurse = asImpl().checkTemporarilyEscapable(TE);
715+
} else if (auto OSE = dyn_cast<ObjCSelectorExpr>(E)) {
716+
recurse = asImpl().checkObjCSelector(OSE);
715717
}
716718

717719
// Error handling validation (via checkTopLevelEffects) happens after
@@ -2268,6 +2270,10 @@ class ApplyClassifier {
22682270
return ShouldRecurse;
22692271
}
22702272

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

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

@@ -2534,6 +2544,10 @@ class ApplyClassifier {
25342544
return ShouldRecurse;
25352545
}
25362546

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

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

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

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

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