1
1
#![ deny( rustc:: untranslatable_diagnostic) ]
2
2
#![ deny( rustc:: diagnostic_outside_of_impl) ]
3
- use rustc_data_structures:: fx:: FxIndexMap ;
3
+ use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
4
4
use rustc_index:: bit_set:: BitSet ;
5
5
use rustc_middle:: mir:: {
6
6
self , BasicBlock , Body , CallReturnPlaces , Location , Place , TerminatorEdges ,
@@ -251,9 +251,9 @@ struct PoloniusOutOfScopePrecomputer<'a, 'tcx> {
251
251
body : & ' a Body < ' tcx > ,
252
252
regioncx : & ' a RegionInferenceContext < ' tcx > ,
253
253
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 > ,
257
257
}
258
258
259
259
impl < ' a , ' tcx > PoloniusOutOfScopePrecomputer < ' a , ' tcx > {
@@ -272,6 +272,7 @@ impl<'a, 'tcx> PoloniusOutOfScopePrecomputer<'a, 'tcx> {
272
272
) ;
273
273
is_placeholder
274
274
} )
275
+ . map ( |r| regioncx. constraint_sccs . scc ( r) )
275
276
. collect ( ) ;
276
277
277
278
Self {
@@ -281,7 +282,7 @@ impl<'a, 'tcx> PoloniusOutOfScopePrecomputer<'a, 'tcx> {
281
282
regioncx,
282
283
loans_out_of_scope_at_location : FxIndexMap :: default ( ) ,
283
284
placeholders,
284
- reachability : BitSet :: new_empty ( regioncx. constraint_sccs . num_sccs ( ) ) ,
285
+ reachability : BitSet :: new_empty ( regioncx. regions ( ) . count ( ) ) ,
285
286
reachability_stack : vec ! [ ] ,
286
287
}
287
288
}
@@ -302,38 +303,51 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
302
303
// regions via member constraints. (The `OutOfScopePrecomputer` wouldn't be called on a
303
304
// region that outlives free regions via outlives constraints.)
304
305
305
- let liveness = & self . regioncx . liveness_constraints ;
306
306
let sccs = & self . regioncx . constraint_sccs ;
307
+ let member_constraints = & self . regioncx . member_constraints ;
307
308
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) ;
311
311
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) ;
313
315
314
- while let Some ( scc) = self . reachability_stack . pop ( ) {
315
316
// Handle successors of this SCC:
316
317
//
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
325
319
//
326
320
// The issuing region can flow into the choice regions here, and they are either:
327
321
// - placeholders or free regions themselves,
328
322
// - or also transitively outlive a free region.
329
323
//
330
324
// That is to say, if there are member constraints here, the loan escapes the
331
325
// 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
+ {
333
333
self . reachability_stack . clear ( ) ;
334
334
self . reachability . clear ( ) ;
335
335
return ;
336
336
}
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
+ }
337
351
}
338
352
339
353
// We visit one BB at a time. The complication is that we may start in the
@@ -364,23 +378,10 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
364
378
// live regions.
365
379
let mut issuing_region_can_reach_live_regions = false ;
366
380
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) {
384
385
issuing_region_can_reach_live_regions = true ;
385
386
break ;
386
387
}
@@ -431,7 +432,7 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
431
432
self . visited . clear ( ) ;
432
433
self . reachability . clear ( ) ;
433
434
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" ) ;
435
436
}
436
437
}
437
438
0 commit comments