Skip to content

Commit 7cec26c

Browse files
committed
DiagnoseInfiniteRecursion: handle throwing functions.
Means: handle try_apply https://bugs.swift.org/browse/SR-13568 rdar://69235604
1 parent e930b2b commit 7cec26c

File tree

2 files changed

+60
-54
lines changed

2 files changed

+60
-54
lines changed

lib/SILOptimizer/Mandatory/DiagnoseInfiniteRecursion.cpp

Lines changed: 56 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -39,72 +39,75 @@ static void diagnose(ASTContext &Context, SourceLoc loc, Diag<T...> diag,
3939
diag, std::forward<U>(args)...);
4040
}
4141

42-
static bool hasRecursiveCallInPath(SILBasicBlock &Block,
43-
SILFunction *Target,
44-
ModuleDecl *TargetModule) {
42+
static bool hasRecursiveCallInBlock(SILBasicBlock &Block,
43+
SILFunction *Target) {
4544
// Process all instructions in the block to find applies that reference
4645
// the parent function. Also looks through vtables for statically
4746
// dispatched (witness) methods.
4847
for (auto &I : Block) {
49-
auto *AI = dyn_cast<ApplyInst>(&I);
50-
if (AI && AI->getCalleeFunction() && AI->getCalleeFunction() == Target)
51-
return true;
48+
FullApplySite FAI = FullApplySite::isa(&I);
49+
if (!FAI)
50+
continue;
51+
52+
if (SILFunction *calledFn = FAI.getReferencedFunctionOrNull()) {
53+
if (calledFn == Target)
54+
return true;
55+
continue;
56+
}
5257

53-
if (FullApplySite FAI = FullApplySite::isa(&I)) {
54-
// Don't touch dynamic dispatch.
55-
const auto callee = FAI.getCallee();
56-
if (isa<SuperMethodInst>(callee) ||
57-
isa<ObjCSuperMethodInst>(callee) ||
58-
isa<ObjCMethodInst>(callee)) {
58+
// Don't touch dynamic dispatch.
59+
const auto callee = FAI.getCallee();
60+
if (isa<SuperMethodInst>(callee) ||
61+
isa<ObjCSuperMethodInst>(callee) ||
62+
isa<ObjCMethodInst>(callee)) {
63+
continue;
64+
}
65+
66+
auto &M = FAI.getModule();
67+
if (auto *CMI = dyn_cast<ClassMethodInst>(callee)) {
68+
auto ClassType = CMI->getOperand()->getType().getASTType();
69+
70+
// FIXME: If we're not inside the module context of the method,
71+
// we may have to deserialize vtables. If the serialized tables
72+
// are damaged, the pass will crash.
73+
//
74+
// Though, this has the added bonus of not looking into vtables
75+
// outside the current module. Because we're not doing IPA, let
76+
// alone cross-module IPA, this is all well and good.
77+
auto *CD = ClassType.getClassOrBoundGenericClass();
78+
if (CD && CD->getModuleContext() != Target->getModule().getSwiftModule()) {
5979
continue;
6080
}
6181

62-
auto &M = FAI.getModule();
63-
if (auto *CMI = dyn_cast<ClassMethodInst>(callee)) {
64-
auto ClassType = CMI->getOperand()->getType().getASTType();
65-
66-
// FIXME: If we're not inside the module context of the method,
67-
// we may have to deserialize vtables. If the serialized tables
68-
// are damaged, the pass will crash.
69-
//
70-
// Though, this has the added bonus of not looking into vtables
71-
// outside the current module. Because we're not doing IPA, let
72-
// alone cross-module IPA, this is all well and good.
73-
auto *CD = ClassType.getClassOrBoundGenericClass();
74-
if (CD && CD->getModuleContext() != TargetModule) {
75-
continue;
76-
}
77-
78-
if (!calleesAreStaticallyKnowable(FAI.getModule(), CMI->getMember())) {
79-
continue;
80-
}
81-
82-
// The "statically knowable" check just means that we have all the
83-
// callee candidates available for analysis. We still need to check
84-
// if the current function has a known override point.
85-
auto *method = CMI->getMember().getAbstractFunctionDecl();
86-
if (method->isOverridden()) {
87-
continue;
88-
}
89-
90-
auto *F = getTargetClassMethod(M, CD, CMI);
91-
if (F == Target)
92-
return true;
82+
if (!calleesAreStaticallyKnowable(FAI.getModule(), CMI->getMember())) {
83+
continue;
84+
}
9385

86+
// The "statically knowable" check just means that we have all the
87+
// callee candidates available for analysis. We still need to check
88+
// if the current function has a known override point.
89+
auto *method = CMI->getMember().getAbstractFunctionDecl();
90+
if (method->isOverridden()) {
9491
continue;
9592
}
9693

97-
if (auto *WMI = dyn_cast<WitnessMethodInst>(callee)) {
98-
SILFunction *F;
99-
SILWitnessTable *WT;
94+
auto *F = getTargetClassMethod(M, CD, CMI);
95+
if (F == Target)
96+
return true;
10097

101-
std::tie(F, WT) = M.lookUpFunctionInWitnessTable(
102-
WMI->getConformance(), WMI->getMember());
103-
if (F == Target)
104-
return true;
98+
continue;
99+
}
105100

106-
continue;
107-
}
101+
if (auto *WMI = dyn_cast<WitnessMethodInst>(callee)) {
102+
SILFunction *F;
103+
SILWitnessTable *WT;
104+
105+
std::tie(F, WT) = M.lookUpFunctionInWitnessTable(
106+
WMI->getConformance(), WMI->getMember());
107+
if (F == Target)
108+
return true;
109+
110+
continue;
108111
}
109112
}
110113
return false;
@@ -138,7 +141,6 @@ static bool hasInfinitelyRecursiveApply(SILFunction *targetFn) {
138141
// We return true if we found any recursion and did not find any
139142
// non-recursive, function-exiting blocks.
140143
bool foundRecursion = false;
141-
auto *targetModule = targetFn->getModule().getSwiftModule();
142144

143145
while (!workList.empty()) {
144146
SILBasicBlock *curBlock = workList.pop_back_val();
@@ -153,7 +155,7 @@ static bool hasInfinitelyRecursiveApply(SILFunction *targetFn) {
153155
// We're looking for functions that are recursive on _all_ paths. If this
154156
// block is recursive, mark that we found recursion and check the next
155157
// block in the work list.
156-
if (hasRecursiveCallInPath(*curBlock, targetFn, targetModule)) {
158+
if (hasRecursiveCallInBlock(*curBlock, targetFn)) {
157159
foundRecursion = true;
158160
continue;
159161
}

test/SILOptimizer/infinite_recursion.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ func a() { // expected-warning {{all paths through this function will call itse
55
a()
66
}
77

8+
func throwing_func() throws { // expected-warning {{all paths through this function will call itself}}
9+
try throwing_func()
10+
}
11+
812
func b(_ x : Int) { // expected-warning {{all paths through this function will call itself}}
913
if x != 0 {
1014
b(x)

0 commit comments

Comments
 (0)