@@ -5,7 +5,7 @@ use std::fs;
55use std:: path:: PathBuf ;
66
77use rustc:: mir:: { self , traversal, BasicBlock , Location } ;
8- use rustc:: ty:: TyCtxt ;
8+ use rustc:: ty:: { self , TyCtxt } ;
99use rustc_data_structures:: work_queue:: WorkQueue ;
1010use rustc_hir:: def_id:: DefId ;
1111use rustc_index:: bit_set:: BitSet ;
@@ -238,10 +238,15 @@ where
238238 }
239239 }
240240
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+ ) ;
245250 }
246251
247252 Call { cleanup, ref destination, ref func, ref args, .. } => {
@@ -287,6 +292,66 @@ where
287292 dirty_queue. insert ( bb) ;
288293 }
289294 }
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+ }
290355}
291356
292357// Graphviz
0 commit comments