@@ -245,7 +245,7 @@ pub fn reachable<'a, 'tcx>(
245
245
/// Returns a `BitSet` containing all basic blocks reachable from the `START_BLOCK`.
246
246
pub fn reachable_as_bitset ( body : & Body < ' _ > ) -> BitSet < BasicBlock > {
247
247
let mut iter = preorder ( body) ;
248
- iter . by_ref ( ) . for_each ( drop ) ;
248
+ while let Some ( _ ) = iter . next ( ) { }
249
249
iter. visited
250
250
}
251
251
@@ -279,3 +279,97 @@ pub fn reverse_postorder<'a, 'tcx>(
279
279
{
280
280
body. basic_blocks . reverse_postorder ( ) . iter ( ) . map ( |& bb| ( bb, & body. basic_blocks [ bb] ) )
281
281
}
282
+
283
+ /// Traversal of a [`Body`] that tries to avoid unreachable blocks in a monomorphized [`Instance`].
284
+ ///
285
+ /// This is allowed to have false positives; blocks may be visited even if they are not actually
286
+ /// reachable.
287
+ ///
288
+ /// Such a traversal is mostly useful because it lets us skip lowering the `false` side
289
+ /// of `if <T as Trait>::CONST`, as well as [`NullOp::UbChecks`].
290
+ ///
291
+ /// [`NullOp::UbChecks`]: rustc_middle::mir::NullOp::UbChecks
292
+ pub fn mono_reachable < ' a , ' tcx > (
293
+ body : & ' a Body < ' tcx > ,
294
+ tcx : TyCtxt < ' tcx > ,
295
+ instance : Instance < ' tcx > ,
296
+ ) -> MonoReachable < ' a , ' tcx > {
297
+ MonoReachable :: new ( body, tcx, instance)
298
+ }
299
+
300
+ /// [`MonoReachable`] internally accumulates a [`BitSet`] of visited blocks. This is just a
301
+ /// convenience function to run that traversal then extract its set of reached blocks.
302
+ pub fn mono_reachable_as_bitset < ' a , ' tcx > (
303
+ body : & ' a Body < ' tcx > ,
304
+ tcx : TyCtxt < ' tcx > ,
305
+ instance : Instance < ' tcx > ,
306
+ ) -> BitSet < BasicBlock > {
307
+ let mut iter = mono_reachable ( body, tcx, instance) ;
308
+ while let Some ( _) = iter. next ( ) { }
309
+ iter. visited
310
+ }
311
+
312
+ pub struct MonoReachable < ' a , ' tcx > {
313
+ body : & ' a Body < ' tcx > ,
314
+ tcx : TyCtxt < ' tcx > ,
315
+ instance : Instance < ' tcx > ,
316
+ visited : BitSet < BasicBlock > ,
317
+ // Other traversers track their worklist in a Vec. But we don't care about order, so we can
318
+ // store ours in a BitSet and thus save allocations because BitSet has a small size
319
+ // optimization.
320
+ worklist : BitSet < BasicBlock > ,
321
+ }
322
+
323
+ impl < ' a , ' tcx > MonoReachable < ' a , ' tcx > {
324
+ pub fn new (
325
+ body : & ' a Body < ' tcx > ,
326
+ tcx : TyCtxt < ' tcx > ,
327
+ instance : Instance < ' tcx > ,
328
+ ) -> MonoReachable < ' a , ' tcx > {
329
+ let mut worklist = BitSet :: new_empty ( body. basic_blocks . len ( ) ) ;
330
+ worklist. insert ( START_BLOCK ) ;
331
+ MonoReachable {
332
+ body,
333
+ tcx,
334
+ instance,
335
+ visited : BitSet :: new_empty ( body. basic_blocks . len ( ) ) ,
336
+ worklist,
337
+ }
338
+ }
339
+
340
+ fn add_work ( & mut self , blocks : impl IntoIterator < Item = BasicBlock > ) {
341
+ for block in blocks. into_iter ( ) {
342
+ if !self . visited . contains ( block) {
343
+ self . worklist . insert ( block) ;
344
+ }
345
+ }
346
+ }
347
+ }
348
+
349
+ impl < ' a , ' tcx > Iterator for MonoReachable < ' a , ' tcx > {
350
+ type Item = ( BasicBlock , & ' a BasicBlockData < ' tcx > ) ;
351
+
352
+ fn next ( & mut self ) -> Option < ( BasicBlock , & ' a BasicBlockData < ' tcx > ) > {
353
+ while let Some ( idx) = self . worklist . iter ( ) . next ( ) {
354
+ self . worklist . remove ( idx) ;
355
+ if !self . visited . insert ( idx) {
356
+ continue ;
357
+ }
358
+
359
+ let data = & self . body [ idx] ;
360
+
361
+ if let Some ( ( bits, targets) ) =
362
+ Body :: try_const_mono_switchint ( self . tcx , self . instance , data)
363
+ {
364
+ let target = targets. target_for_value ( bits) ;
365
+ self . add_work ( [ target] ) ;
366
+ } else {
367
+ self . add_work ( data. terminator ( ) . successors ( ) ) ;
368
+ }
369
+
370
+ return Some ( ( idx, data) ) ;
371
+ }
372
+
373
+ None
374
+ }
375
+ }
0 commit comments