11#![ deny( rustc:: untranslatable_diagnostic) ]
22#![ deny( rustc:: diagnostic_outside_of_impl) ]
3- use rustc_data_structures:: fx:: FxIndexMap ;
3+ use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
44use rustc_index:: bit_set:: BitSet ;
55use rustc_middle:: mir:: {
66 self , BasicBlock , Body , CallReturnPlaces , Location , Place , TerminatorEdges ,
@@ -251,9 +251,9 @@ struct PoloniusOutOfScopePrecomputer<'a, 'tcx> {
251251 body : & ' a Body < ' tcx > ,
252252 regioncx : & ' a RegionInferenceContext < ' tcx > ,
253253 loans_out_of_scope_at_location : FxIndexMap < Location , Vec < BorrowIndex > > ,
254- placeholders : Vec < RegionVid > ,
255- reachability : BitSet < ConstraintSccIndex > ,
256- reachability_stack : Vec < ConstraintSccIndex > ,
254+ placeholders : FxHashSet < ConstraintSccIndex > ,
255+ reachability : BitSet < RegionVid > ,
256+ reachability_stack : Vec < RegionVid > ,
257257}
258258
259259impl < ' a , ' tcx > PoloniusOutOfScopePrecomputer < ' a , ' tcx > {
@@ -272,6 +272,7 @@ impl<'a, 'tcx> PoloniusOutOfScopePrecomputer<'a, 'tcx> {
272272 ) ;
273273 is_placeholder
274274 } )
275+ . map ( |r| regioncx. constraint_sccs . scc ( r) )
275276 . collect ( ) ;
276277
277278 Self {
@@ -281,7 +282,7 @@ impl<'a, 'tcx> PoloniusOutOfScopePrecomputer<'a, 'tcx> {
281282 regioncx,
282283 loans_out_of_scope_at_location : FxIndexMap :: default ( ) ,
283284 placeholders,
284- reachability : BitSet :: new_empty ( regioncx. constraint_sccs . num_sccs ( ) ) ,
285+ reachability : BitSet :: new_empty ( regioncx. regions ( ) . count ( ) ) ,
285286 reachability_stack : vec ! [ ] ,
286287 }
287288 }
@@ -302,38 +303,51 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
302303 // regions via member constraints. (The `OutOfScopePrecomputer` wouldn't be called on a
303304 // region that outlives free regions via outlives constraints.)
304305
305- let liveness = & self . regioncx . liveness_constraints ;
306306 let sccs = & self . regioncx . constraint_sccs ;
307+ let member_constraints = & self . regioncx . member_constraints ;
307308
308- let issuing_region_scc = sccs. scc ( issuing_region) ;
309- self . reachability_stack . push ( issuing_region_scc) ;
310- self . reachability . insert ( issuing_region_scc) ;
309+ self . reachability_stack . push ( issuing_region) ;
310+ self . reachability . insert ( issuing_region) ;
311311
312- let member_constraints = & self . regioncx . member_constraints ;
312+ let static_region = self . regioncx . universal_regions ( ) . fr_static ;
313+ while let Some ( region) = self . reachability_stack . pop ( ) {
314+ let scc = sccs. scc ( region) ;
313315
314- while let Some ( scc) = self . reachability_stack . pop ( ) {
315316 // Handle successors of this SCC:
316317 //
317- // 1. Push outlives successors to the worklist stack
318- for & succ_scc in sccs. successors ( scc) {
319- if self . reachability . insert ( succ_scc) {
320- self . reachability_stack . push ( succ_scc) ;
321- }
322- }
323-
324- // 2. Deal with member constraints
318+ // 1. Via member constraints
325319 //
326320 // The issuing region can flow into the choice regions here, and they are either:
327321 // - placeholders or free regions themselves,
328322 // - or also transitively outlive a free region.
329323 //
330324 // That is to say, if there are member constraints here, the loan escapes the
331325 // function and cannot go out of scope. We can early return.
332- if member_constraints. indices ( scc) . next ( ) . is_some ( ) {
326+ //
327+ // 2. Via placeholders
328+ //
329+ // If the issuing region outlives placeholders, its loan escapes the function and
330+ // cannot go out of scope. We can early return.
331+ if member_constraints. indices ( scc) . next ( ) . is_some ( ) || self . placeholders . contains ( & scc)
332+ {
333333 self . reachability_stack . clear ( ) ;
334334 self . reachability . clear ( ) ;
335335 return ;
336336 }
337+
338+ // 3. Via outlives successors, which we want to record and traverse, so we add them
339+ // to the worklist stack
340+ let successors = self . regioncx . constraint_graph . outgoing_edges (
341+ region,
342+ & self . regioncx . constraints ,
343+ static_region,
344+ ) ;
345+ for outlives_constraint in successors {
346+ let succ = outlives_constraint. sub ;
347+ if self . reachability . insert ( succ) {
348+ self . reachability_stack . push ( succ) ;
349+ }
350+ }
337351 }
338352
339353 // We visit one BB at a time. The complication is that we may start in the
@@ -364,23 +378,10 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
364378 // live regions.
365379 let mut issuing_region_can_reach_live_regions = false ;
366380
367- // Check reachability of all live regions:
368- // - the local regions that are live at this point,
369- // - the placeholders, which are live at all points and don't need liveness to be
370- // computed, and are thus absent from the liveness values.
371- //
372- // As mentioned above, we don't need to check for free regions, if the issuing
373- // region outlived a free region via outlives constraints, we wouldn't need to
374- // compute its loan's scope.
375- for live_region in
376- liveness. live_regions_at ( location) . chain ( self . placeholders . iter ( ) . copied ( ) )
377- {
378- let live_region_scc = sccs. scc ( live_region) ;
379-
380- // If a single live region is reachable from the issuing region, then the loan
381- // is still live at this point. We can stop checking other live regions at this
382- // location, and go to the next location.
383- if self . reachability . contains ( live_region_scc) {
381+ // Check whether the issuing region can reach local regions that are live at this
382+ // point.
383+ for reachable_region in self . reachability . iter ( ) {
384+ if self . regioncx . liveness_constraints . contains ( reachable_region, location) {
384385 issuing_region_can_reach_live_regions = true ;
385386 break ;
386387 }
@@ -431,7 +432,7 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
431432 self . visited . clear ( ) ;
432433 self . reachability . clear ( ) ;
433434 assert ! ( self . visit_stack. is_empty( ) , "visit stack should be empty" ) ;
434- assert ! ( self . reachability_stack. is_empty( ) , "reachablity stack should be empty" ) ;
435+ assert ! ( self . reachability_stack. is_empty( ) , "reachability stack should be empty" ) ;
435436 }
436437}
437438
0 commit comments