@@ -64,15 +64,15 @@ fn process<'tcx>(
6464 typing_env : ty:: TypingEnv < ' tcx > ,
6565 caller : ty:: Instance < ' tcx > ,
6666 target : LocalDefId ,
67- seen : & mut FxHashSet < ty:: Instance < ' tcx > > ,
67+ seen : & mut FxHashMap < ty:: Instance < ' tcx > , bool > ,
6868 involved : & mut FxHashSet < LocalDefId > ,
6969 recursion_limiter : & mut FxHashMap < DefId , usize > ,
7070 recursion_limit : Limit ,
7171) -> bool {
7272 trace ! ( %caller) ;
73- let mut cycle_found = false ;
73+ let mut reaches_root = false ;
7474
75- for & ( callee , args) in tcx. mir_inliner_callees ( caller. def ) {
75+ for & ( callee_def_id , args) in tcx. mir_inliner_callees ( caller. def ) {
7676 let Ok ( args) = caller. try_instantiate_mir_and_normalize_erasing_regions (
7777 tcx,
7878 typing_env,
@@ -81,14 +81,17 @@ fn process<'tcx>(
8181 trace ! ( ?caller, ?typing_env, ?args, "cannot normalize, skipping" ) ;
8282 continue ;
8383 } ;
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" ) ;
8687 continue ;
8788 } ;
8889
8990 // Found a path.
9091 if callee. def_id ( ) == target. to_def_id ( ) {
91- cycle_found = true ;
92+ reaches_root = true ;
93+ seen. insert ( callee, true ) ;
94+ continue ;
9295 }
9396
9497 if tcx. is_constructor ( callee. def_id ( ) ) {
@@ -101,10 +104,17 @@ fn process<'tcx>(
101104 continue ;
102105 }
103106
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 ) ;
105115 let recursion = recursion_limiter. entry ( callee. def_id ( ) ) . or_default ( ) ;
106116 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) {
108118 * recursion += 1 ;
109119 ensure_sufficient_stack ( || {
110120 process (
@@ -122,17 +132,19 @@ fn process<'tcx>(
122132 // Pessimistically assume that there could be recursion.
123133 true
124134 } ;
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) ;
131142 }
143+ reaches_root = true ;
132144 }
133145 }
134146
135- cycle_found
147+ reaches_root
136148}
137149
138150#[ instrument( level = "debug" , skip( tcx) , ret) ]
@@ -166,7 +178,7 @@ pub(crate) fn mir_callgraph_cyclic<'tcx>(
166178 typing_env,
167179 root_instance,
168180 root,
169- & mut FxHashSet :: default ( ) ,
181+ & mut FxHashMap :: default ( ) ,
170182 & mut involved,
171183 & mut FxHashMap :: default ( ) ,
172184 recursion_limit,
0 commit comments