Skip to content

Commit f730ff1

Browse files
committed
Disregard Overridden Candidates in Infinite Recursion Check
Disregard candidates that have known override points because those points are possible targets for dynamic dispatch. This removes a class of false positives involving classes with known override points in the module, as is this case in many node-based data structures. rdar://70410948
1 parent 3029ce8 commit f730ff1

File tree

2 files changed

+30
-4
lines changed

2 files changed

+30
-4
lines changed

lib/SILOptimizer/Mandatory/DiagnoseInfiniteRecursion.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,11 @@ static bool hasRecursiveCallInPath(SILBasicBlock &Block,
5252

5353
if (FullApplySite FAI = FullApplySite::isa(&I)) {
5454
// Don't touch dynamic dispatch.
55-
if (isa<ObjCMethodInst>(FAI.getCallee()))
55+
if (isa<SuperMethodInst>(FAI.getCallee()) ||
56+
isa<ObjCSuperMethodInst>(FAI.getCallee()) ||
57+
isa<ObjCMethodInst>(FAI.getCallee())) {
5658
continue;
59+
}
5760

5861
auto &M = FAI.getModule();
5962
if (auto *CMI = dyn_cast<ClassMethodInst>(FAI.getCallee())) {
@@ -71,6 +74,18 @@ static bool hasRecursiveCallInPath(SILBasicBlock &Block,
7174
continue;
7275
}
7376

77+
if (!calleesAreStaticallyKnowable(FAI.getModule(), CMI->getMember())) {
78+
continue;
79+
}
80+
81+
// The "statically knowable" check just means that we have all the
82+
// callee candidates available for analysis. We still need to check
83+
// if the current function has a known override point.
84+
auto *method = CMI->getMember().getAbstractFunctionDecl();
85+
if (method->isOverridden()) {
86+
continue;
87+
}
88+
7489
auto *F = getTargetClassMethod(M, CD, CMI);
7590
if (F == Target)
7691
return true;

test/SILOptimizer/infinite_recursion.swift

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %target-swift-frontend -emit-sil -primary-file %s -o /dev/null -verify
2-
// RUN: %target-swift-frontend -emit-sil -primary-file %s -o /dev/null -verify
1+
// RUN: %target-swift-frontend -emit-sil %s -o /dev/null -verify
2+
// RUN: %target-swift-frontend -emit-sil %s -o /dev/null -verify
33

44
func a() { // expected-warning {{all paths through this function will call itself}}
55
a()
@@ -123,7 +123,7 @@ class S {
123123
return a()
124124
}
125125

126-
func b() { // expected-warning {{all paths through this function will call itself}}
126+
func b() { // No warning - has a known override.
127127
var i = 0
128128
repeat {
129129
i += 1
@@ -171,3 +171,14 @@ func factorial(_ n : UInt) -> UInt { // expected-warning {{all paths through thi
171171
func tr(_ key: String) -> String { // expected-warning {{all paths through this function will call itself}}
172172
return tr(key) ?? key // expected-warning {{left side of nil coalescing operator '??' has non-optional type}}
173173
}
174+
175+
class Node {
176+
var parent: Node?
177+
var rootNode: RootNode {
178+
return parent!.rootNode // No warning - has an override.
179+
}
180+
}
181+
182+
class RootNode: Node {
183+
override var rootNode: RootNode { return self }
184+
}

0 commit comments

Comments
 (0)