@@ -5,7 +5,7 @@ use std::fs;
5
5
use std:: path:: PathBuf ;
6
6
7
7
use rustc:: mir:: { self , traversal, BasicBlock , Location } ;
8
- use rustc:: ty:: TyCtxt ;
8
+ use rustc:: ty:: { self , TyCtxt } ;
9
9
use rustc_data_structures:: work_queue:: WorkQueue ;
10
10
use rustc_hir:: def_id:: DefId ;
11
11
use rustc_index:: bit_set:: BitSet ;
@@ -238,10 +238,15 @@ where
238
238
}
239
239
}
240
240
241
- SwitchInt { ref targets, .. } => {
242
- for target in targets {
243
- self . propagate_bits_into_entry_set_for ( in_out, * target, dirty_list) ;
244
- }
241
+ SwitchInt { ref targets, ref values, ref discr, .. } => {
242
+ self . propagate_bits_into_switch_int_successors (
243
+ in_out,
244
+ ( bb, bb_data) ,
245
+ dirty_list,
246
+ discr,
247
+ & * values,
248
+ & * targets,
249
+ ) ;
245
250
}
246
251
247
252
Call { cleanup, ref destination, ref func, ref args, .. } => {
@@ -287,6 +292,66 @@ where
287
292
dirty_queue. insert ( bb) ;
288
293
}
289
294
}
295
+
296
+ fn propagate_bits_into_switch_int_successors (
297
+ & mut self ,
298
+ in_out : & mut BitSet < A :: Idx > ,
299
+ ( bb, bb_data) : ( BasicBlock , & mir:: BasicBlockData < ' tcx > ) ,
300
+ dirty_list : & mut WorkQueue < BasicBlock > ,
301
+ switch_on : & mir:: Operand < ' tcx > ,
302
+ values : & [ u128 ] ,
303
+ targets : & [ BasicBlock ] ,
304
+ ) {
305
+ match bb_data. statements . last ( ) . map ( |stmt| & stmt. kind ) {
306
+ // Look at the last statement to see if it is an assignment of an enum discriminant to
307
+ // the local that determines the target of a `SwitchInt` like so:
308
+ // _42 = discriminant(..)
309
+ // SwitchInt(_42, ..)
310
+ Some ( mir:: StatementKind :: Assign ( box ( lhs, mir:: Rvalue :: Discriminant ( enum_) ) ) )
311
+ if Some ( lhs) == switch_on. place ( ) =>
312
+ {
313
+ let adt = match enum_. ty ( self . body , self . tcx ) . ty . kind {
314
+ ty:: Adt ( def, _) => def,
315
+ _ => bug ! ( "Switch on discriminant of non-ADT" ) ,
316
+ } ;
317
+
318
+ // MIR building adds discriminants to the `values` array in the same order as they
319
+ // are yielded by `AdtDef::discriminants`. We rely on this to match each
320
+ // discriminant in `values` to its corresponding variant in linear time.
321
+ let mut tmp = BitSet :: new_empty ( in_out. domain_size ( ) ) ;
322
+ let mut discriminants = adt. discriminants ( self . tcx ) ;
323
+ for ( value, target) in values. iter ( ) . zip ( targets. iter ( ) . copied ( ) ) {
324
+ let ( variant_idx, _) =
325
+ discriminants. find ( |& ( _, discr) | discr. val == * value) . expect (
326
+ "Order of `AdtDef::discriminants` differed \
327
+ from that of `SwitchInt::values`",
328
+ ) ;
329
+
330
+ tmp. overwrite ( in_out) ;
331
+ self . analysis . apply_discriminant_switch_effect (
332
+ & mut tmp,
333
+ bb,
334
+ enum_,
335
+ adt,
336
+ variant_idx,
337
+ ) ;
338
+ self . propagate_bits_into_entry_set_for ( & tmp, target, dirty_list) ;
339
+ }
340
+
341
+ std:: mem:: drop ( tmp) ;
342
+
343
+ // Propagate dataflow state along the "otherwise" edge.
344
+ let otherwise = targets. last ( ) . copied ( ) . unwrap ( ) ;
345
+ self . propagate_bits_into_entry_set_for ( & in_out, otherwise, dirty_list) ;
346
+ }
347
+
348
+ _ => {
349
+ for target in targets. iter ( ) . copied ( ) {
350
+ self . propagate_bits_into_entry_set_for ( & in_out, target, dirty_list) ;
351
+ }
352
+ }
353
+ }
354
+ }
290
355
}
291
356
292
357
// Graphviz
0 commit comments