@@ -64,15 +64,15 @@ fn process<'tcx>(
64
64
typing_env : ty:: TypingEnv < ' tcx > ,
65
65
caller : ty:: Instance < ' tcx > ,
66
66
target : LocalDefId ,
67
- seen : & mut FxHashSet < ty:: Instance < ' tcx > > ,
67
+ seen : & mut FxHashMap < ty:: Instance < ' tcx > , bool > ,
68
68
involved : & mut FxHashSet < LocalDefId > ,
69
69
recursion_limiter : & mut FxHashMap < DefId , usize > ,
70
70
recursion_limit : Limit ,
71
71
) -> bool {
72
72
trace ! ( %caller) ;
73
- let mut cycle_found = false ;
73
+ let mut reaches_root = false ;
74
74
75
- for & ( callee , args) in tcx. mir_inliner_callees ( caller. def ) {
75
+ for & ( callee_def_id , args) in tcx. mir_inliner_callees ( caller. def ) {
76
76
let Ok ( args) = caller. try_instantiate_mir_and_normalize_erasing_regions (
77
77
tcx,
78
78
typing_env,
@@ -81,14 +81,17 @@ fn process<'tcx>(
81
81
trace ! ( ?caller, ?typing_env, ?args, "cannot normalize, skipping" ) ;
82
82
continue ;
83
83
} ;
84
- let Ok ( Some ( callee) ) = ty:: Instance :: try_resolve ( tcx, typing_env, callee, args) else {
85
- trace ! ( ?callee, "cannot resolve, skipping" ) ;
84
+ let Ok ( Some ( callee) ) = ty:: Instance :: try_resolve ( tcx, typing_env, callee_def_id, args)
85
+ else {
86
+ trace ! ( ?callee_def_id, "cannot resolve, skipping" ) ;
86
87
continue ;
87
88
} ;
88
89
89
90
// Found a path.
90
91
if callee. def_id ( ) == target. to_def_id ( ) {
91
- cycle_found = true ;
92
+ reaches_root = true ;
93
+ seen. insert ( callee, true ) ;
94
+ continue ;
92
95
}
93
96
94
97
if tcx. is_constructor ( callee. def_id ( ) ) {
@@ -101,10 +104,17 @@ fn process<'tcx>(
101
104
continue ;
102
105
}
103
106
104
- if seen. insert ( callee) {
107
+ let callee_reaches_root = if let Some ( & c) = seen. get ( & callee) {
108
+ // Even if we have seen this callee before, and thus don't need
109
+ // to recurse into it, we still need to propagate whether it reaches
110
+ // the root so that we can mark all the involved callers, in case we
111
+ // end up reaching that same recursive callee through some *other* cycle.
112
+ c
113
+ } else {
114
+ seen. insert ( callee, false ) ;
105
115
let recursion = recursion_limiter. entry ( callee. def_id ( ) ) . or_default ( ) ;
106
116
trace ! ( ?callee, recursion = * recursion) ;
107
- let found_recursion = if recursion_limit. value_within_limit ( * recursion) {
117
+ let callee_reaches_root = if recursion_limit. value_within_limit ( * recursion) {
108
118
* recursion += 1 ;
109
119
ensure_sufficient_stack ( || {
110
120
process (
@@ -122,17 +132,19 @@ fn process<'tcx>(
122
132
// Pessimistically assume that there could be recursion.
123
133
true
124
134
} ;
125
- if found_recursion {
126
- if let Some ( callee) = callee. def_id ( ) . as_local ( ) {
127
- // Calling `optimized_mir` of a non-local definition cannot cycle.
128
- involved. insert ( callee) ;
129
- }
130
- cycle_found = true ;
135
+ seen. insert ( callee, callee_reaches_root) ;
136
+ callee_reaches_root
137
+ } ;
138
+ if callee_reaches_root {
139
+ if let Some ( callee_def_id) = callee. def_id ( ) . as_local ( ) {
140
+ // Calling `optimized_mir` of a non-local definition cannot cycle.
141
+ involved. insert ( callee_def_id) ;
131
142
}
143
+ reaches_root = true ;
132
144
}
133
145
}
134
146
135
- cycle_found
147
+ reaches_root
136
148
}
137
149
138
150
#[ instrument( level = "debug" , skip( tcx) , ret) ]
@@ -166,7 +178,7 @@ pub(crate) fn mir_callgraph_cyclic<'tcx>(
166
178
typing_env,
167
179
root_instance,
168
180
root,
169
- & mut FxHashSet :: default ( ) ,
181
+ & mut FxHashMap :: default ( ) ,
170
182
& mut involved,
171
183
& mut FxHashMap :: default ( ) ,
172
184
recursion_limit,
0 commit comments