1
1
#![ deny( rustc:: untranslatable_diagnostic) ]
2
2
#![ deny( rustc:: diagnostic_outside_of_impl) ]
3
- use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
4
- use rustc_index:: bit_set:: { BitSet , SparseBitMatrix } ;
3
+ use rustc_data_structures:: fx:: FxIndexMap ;
4
+ use rustc_data_structures:: graph:: WithSuccessors ;
5
+ use rustc_index:: bit_set:: BitSet ;
6
+ use rustc_infer:: infer:: { NllRegionVariableOrigin , RegionVariableOrigin } ;
5
7
use rustc_middle:: mir:: {
6
8
self , BasicBlock , Body , CallReturnPlaces , Location , Place , TerminatorEdges ,
7
9
} ;
@@ -13,8 +15,6 @@ use rustc_mir_dataflow::{self, fmt::DebugWithContext, GenKill};
13
15
use rustc_mir_dataflow:: { Analysis , Direction , Results } ;
14
16
use std:: fmt;
15
17
16
- use crate :: constraints:: ConstraintSccIndex ;
17
- use crate :: region_infer:: values:: PointIndex ;
18
18
use crate :: { places_conflict, BorrowSet , PlaceConflictBias , PlaceExt , RegionInferenceContext } ;
19
19
20
20
/// A tuple with named fields that can hold either the results or the transient state of the
@@ -255,66 +255,17 @@ struct PoloniusOutOfScopePrecomputer<'a, 'tcx> {
255
255
visit_stack : Vec < StackEntry > ,
256
256
body : & ' a Body < ' tcx > ,
257
257
regioncx : & ' a RegionInferenceContext < ' tcx > ,
258
-
259
- sccs_live_at_all_points : FxHashSet < ConstraintSccIndex > ,
260
- live_sccs_per_point : SparseBitMatrix < PointIndex , ConstraintSccIndex > ,
261
-
262
- reachability : BitSet < ConstraintSccIndex > ,
263
- reachability_stack : Vec < ConstraintSccIndex > ,
264
-
265
258
loans_out_of_scope_at_location : FxIndexMap < Location , Vec < BorrowIndex > > ,
266
259
}
267
260
268
261
impl < ' a , ' tcx > PoloniusOutOfScopePrecomputer < ' a , ' tcx > {
269
262
fn new ( body : & ' a Body < ' tcx > , regioncx : & ' a RegionInferenceContext < ' tcx > ) -> Self {
270
- let sccs = regioncx. constraint_sccs ( ) ;
271
- let num_sccs = sccs. num_sccs ( ) ;
272
-
273
- // Compute the list of SCCs that are live at all points, as it will be used for all the
274
- // loan scopes we'll compute.
275
- // FIXME: they're surely already available somewhere.
276
- let sccs_live_at_all_points: FxHashSet < _ > = regioncx
277
- . regions ( )
278
- . filter ( |& r| {
279
- use rustc_infer:: infer:: { NllRegionVariableOrigin , RegionVariableOrigin } ;
280
- let origin = regioncx. var_infos [ r] . origin ;
281
- let live_at_all_points = matches ! (
282
- origin,
283
- RegionVariableOrigin :: Nll (
284
- NllRegionVariableOrigin :: Placeholder ( _)
285
- | NllRegionVariableOrigin :: FreeRegion
286
- )
287
- ) ;
288
- live_at_all_points
289
- } )
290
- . map ( |r| sccs. scc ( r) )
291
- . collect ( ) ;
292
-
293
- // Pre-compute the set of live SCCs per point
294
- let liveness = regioncx. liveness_values ( ) ;
295
- let mut live_sccs_per_point = SparseBitMatrix :: new ( num_sccs) ;
296
-
297
- for region in liveness. rows ( ) {
298
- let scc = sccs. scc ( region) ;
299
- if sccs_live_at_all_points. contains ( & scc) {
300
- continue ;
301
- }
302
- for location in liveness. get_elements ( region) {
303
- let point = liveness. point_from_location ( location) ;
304
- live_sccs_per_point. insert ( point, scc) ;
305
- }
306
- }
307
-
308
263
Self {
309
264
visited : BitSet :: new_empty ( body. basic_blocks . len ( ) ) ,
310
265
visit_stack : vec ! [ ] ,
311
266
body,
312
267
regioncx,
313
268
loans_out_of_scope_at_location : FxIndexMap :: default ( ) ,
314
- sccs_live_at_all_points,
315
- live_sccs_per_point,
316
- reachability : BitSet :: new_empty ( num_sccs) ,
317
- reachability_stack : vec ! [ ] ,
318
269
}
319
270
}
320
271
}
@@ -329,48 +280,44 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
329
280
issuing_region : RegionVid ,
330
281
issued_location : Location ,
331
282
) {
332
- // Let's precompute the reachability set of the issuing region, via reachability on the
333
- // condensation graph. We can also early return when reaching regions that outlive free
334
- // regions via member constraints. (The `OutOfScopePrecomputer` wouldn't be called on a
335
- // region that outlives free regions via outlives constraints.)
336
-
337
283
let sccs = self . regioncx . constraint_sccs ( ) ;
338
-
339
284
let issuing_region_scc = sccs. scc ( issuing_region) ;
340
- self . reachability_stack . push ( issuing_region_scc) ;
341
- self . reachability . insert ( issuing_region_scc) ;
342
285
343
- while let Some ( scc ) = self . reachability_stack . pop ( ) {
344
- // Handle successors of this SCC:
345
- //
286
+ // We first handle the cases where the loan doesn't go out of scope, depending on the issuing
287
+ // region's successors.
288
+ for scc in sccs . depth_first_search ( issuing_region_scc ) {
346
289
// 1. Via member constraints
347
290
//
348
- // The issuing region can flow into the choice regions here , and they are either:
291
+ // The issuing region can flow into the choice regions, and they are either:
349
292
// - placeholders or free regions themselves,
350
293
// - or also transitively outlive a free region.
351
294
//
352
- // That is to say, if there are member constraints here, the loan escapes the
353
- // function and cannot go out of scope. We can early return.
354
- //
295
+ // That is to say, if there are member constraints here, the loan escapes the function
296
+ // and cannot go out of scope. We can early return.
297
+ if self . regioncx . scc_has_member_constraints ( scc) {
298
+ return ;
299
+ }
300
+
355
301
// 2. Via regions that are live at all points: placeholders and free regions.
356
302
//
357
303
// If the issuing region outlives such a region, its loan escapes the function and
358
304
// cannot go out of scope. We can early return.
359
- if self . regioncx . scc_has_member_constraints ( scc)
360
- || self . sccs_live_at_all_points . contains ( & scc)
361
- {
362
- self . reachability_stack . clear ( ) ;
363
- self . reachability . clear ( ) ;
305
+ //
306
+ // FIXME: there must be a cleaner way to find this information. At least, when
307
+ // higher-ranked subtyping is abstracted away from the borrowck main path, we'll only
308
+ // need to check whether this is a universal region.
309
+ //
310
+ let representative = self . regioncx . scc_representatives [ scc] ;
311
+ let origin = self . regioncx . var_infos [ representative] . origin ;
312
+ let live_at_all_points = matches ! (
313
+ origin,
314
+ RegionVariableOrigin :: Nll (
315
+ NllRegionVariableOrigin :: Placeholder ( _) | NllRegionVariableOrigin :: FreeRegion
316
+ )
317
+ ) ;
318
+ if live_at_all_points {
364
319
return ;
365
320
}
366
-
367
- // 3. Via outlives successors, which we want to record and traverse: we add them
368
- // to the worklist stack
369
- for & succ_scc in sccs. successors ( scc) {
370
- if self . reachability . insert ( succ_scc) {
371
- self . reachability_stack . push ( succ_scc) ;
372
- }
373
- }
374
321
}
375
322
376
323
// We visit one BB at a time. The complication is that we may start in the
@@ -397,26 +344,26 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
397
344
for i in lo..=hi {
398
345
let location = Location { block : bb, statement_index : i } ;
399
346
400
- // The loan is out of scope at point `location` if it's not contained within any
401
- // live regions.
347
+ // Check whether the issuing region can reach local regions that are live at this
348
+ // point:
349
+ // - a loan is always live at its issuing location because it can reach the issuing
350
+ // region, which is always live at this location.
351
+ if location == issued_location {
352
+ continue ;
353
+ }
354
+
355
+ // - the loan is out of scope at point `location` if it's not contained within any
356
+ // regions live at this point.
402
357
let mut issuing_region_can_reach_live_regions = false ;
403
358
404
- // Check whether the issuing region can reach local regions that are live at this
405
- // point.
406
- //
407
359
// FIXME: if the issuing region `i` can reach a live region `r` at point `p`, and
408
360
// `r` is live at point `q`, then it's guaranteed that `i` would reach `r` at point
409
361
// `q`. The reachability is location-insensitive, and we could take advantage of
410
362
// that, by jumping to a further point than the next statement. We can jump to the
411
363
// furthest point within the block where `r` is live.
412
364
let point = self . regioncx . liveness_values ( ) . point_from_location ( location) ;
413
- if let Some ( live_sccs) = self . live_sccs_per_point . row ( point) {
414
- for live_scc in live_sccs. iter ( ) {
415
- if self . reachability . contains ( live_scc) {
416
- issuing_region_can_reach_live_regions = true ;
417
- break ;
418
- }
419
- }
365
+ if self . regioncx . live_loans . contains ( point, loan_idx) {
366
+ issuing_region_can_reach_live_regions = true ;
420
367
}
421
368
422
369
// If no live region is reachable from the issuing region, then the loan is
@@ -462,9 +409,7 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
462
409
}
463
410
464
411
self . visited . clear ( ) ;
465
- self . reachability . clear ( ) ;
466
412
assert ! ( self . visit_stack. is_empty( ) , "visit stack should be empty" ) ;
467
- assert ! ( self . reachability_stack. is_empty( ) , "reachability stack should be empty" ) ;
468
413
}
469
414
}
470
415
@@ -495,8 +440,8 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
495
440
}
496
441
497
442
assert_eq ! (
498
- borrows_out_of_scope_at_location , polonius_prec. loans_out_of_scope_at_location,
499
- "the loans out of scope must be the same as the borrows out of scope"
443
+ polonius_prec. loans_out_of_scope_at_location, borrows_out_of_scope_at_location ,
444
+ "the loans out of scope are different from the borrows out of scope"
500
445
) ;
501
446
502
447
borrows_out_of_scope_at_location = polonius_prec. loans_out_of_scope_at_location ;
0 commit comments