@@ -40,6 +40,57 @@ impl<'tcx> MaybePlacesSwitchIntData<'tcx> {
40
40
}
41
41
}
42
42
43
+ impl < ' tcx > MaybePlacesSwitchIntData < ' tcx > {
44
+ fn new (
45
+ tcx : TyCtxt < ' tcx > ,
46
+ body : & Body < ' tcx > ,
47
+ block : mir:: BasicBlock ,
48
+ discr : & mir:: Operand < ' tcx > ,
49
+ ) -> Option < Self > {
50
+ let Some ( discr) = discr. place ( ) else { return None } ;
51
+
52
+ // Inspect a `SwitchInt`-terminated basic block to see if the condition of that `SwitchInt`
53
+ // is an enum discriminant.
54
+ //
55
+ // We expect such blocks to have a call to `discriminant` as their last statement like so:
56
+ // ```text
57
+ // ...
58
+ // _42 = discriminant(_1)
59
+ // SwitchInt(_42, ..)
60
+ // ```
61
+ // If the basic block matches this pattern, this function gathers the place corresponding
62
+ // to the enum (`_1` in the example above) as well as the discriminants.
63
+ let block_data = & body[ block] ;
64
+ for statement in block_data. statements . iter ( ) . rev ( ) {
65
+ match statement. kind {
66
+ mir:: StatementKind :: Assign ( box ( lhs, mir:: Rvalue :: Discriminant ( enum_place) ) )
67
+ if lhs == discr =>
68
+ {
69
+ match enum_place. ty ( body, tcx) . ty . kind ( ) {
70
+ ty:: Adt ( enum_def, _) => {
71
+ return Some ( MaybePlacesSwitchIntData {
72
+ enum_place,
73
+ discriminants : enum_def. discriminants ( tcx) . collect ( ) ,
74
+ index : 0 ,
75
+ } ) ;
76
+ }
77
+
78
+ // `Rvalue::Discriminant` is also used to get the active yield point for a
79
+ // coroutine, but we do not need edge-specific effects in that case. This
80
+ // may change in the future.
81
+ ty:: Coroutine ( ..) => break ,
82
+
83
+ t => bug ! ( "`discriminant` called on unexpected type {:?}" , t) ,
84
+ }
85
+ }
86
+ mir:: StatementKind :: Coverage ( _) => continue ,
87
+ _ => break ,
88
+ }
89
+ }
90
+ None
91
+ }
92
+ }
93
+
43
94
/// `MaybeInitializedPlaces` tracks all places that might be
44
95
/// initialized upon reaching a particular point in the control flow
45
96
/// for a function.
@@ -364,15 +415,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
364
415
return None ;
365
416
}
366
417
367
- discr. place ( ) . and_then ( |discr| {
368
- switch_on_enum_discriminant ( self . tcx , self . body , & self . body [ block] , discr) . map (
369
- |( enum_place, enum_def) | MaybePlacesSwitchIntData {
370
- enum_place,
371
- discriminants : enum_def. discriminants ( self . tcx ) . collect ( ) ,
372
- index : 0 ,
373
- } ,
374
- )
375
- } )
418
+ MaybePlacesSwitchIntData :: new ( self . tcx , self . body , block, discr)
376
419
}
377
420
378
421
fn apply_switch_int_edge_effect (
@@ -483,15 +526,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
483
526
return None ;
484
527
}
485
528
486
- discr. place ( ) . and_then ( |discr| {
487
- switch_on_enum_discriminant ( self . tcx , self . body , & self . body [ block] , discr) . map (
488
- |( enum_place, enum_def) | MaybePlacesSwitchIntData {
489
- enum_place,
490
- discriminants : enum_def. discriminants ( self . tcx ) . collect ( ) ,
491
- index : 0 ,
492
- } ,
493
- )
494
- } )
529
+ MaybePlacesSwitchIntData :: new ( self . tcx , self . body , block, discr)
495
530
}
496
531
497
532
fn apply_switch_int_edge_effect (
@@ -597,45 +632,3 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
597
632
}
598
633
}
599
634
}
600
-
601
- /// Inspect a `SwitchInt`-terminated basic block to see if the condition of that `SwitchInt` is
602
- /// an enum discriminant.
603
- ///
604
- /// We expect such blocks to have a call to `discriminant` as their last statement like so:
605
- ///
606
- /// ```text
607
- /// ...
608
- /// _42 = discriminant(_1)
609
- /// SwitchInt(_42, ..)
610
- /// ```
611
- ///
612
- /// If the basic block matches this pattern, this function returns the place corresponding to the
613
- /// enum (`_1` in the example above) as well as the `AdtDef` of that enum.
614
- fn switch_on_enum_discriminant < ' mir , ' tcx > (
615
- tcx : TyCtxt < ' tcx > ,
616
- body : & ' mir mir:: Body < ' tcx > ,
617
- block : & ' mir mir:: BasicBlockData < ' tcx > ,
618
- switch_on : mir:: Place < ' tcx > ,
619
- ) -> Option < ( mir:: Place < ' tcx > , ty:: AdtDef < ' tcx > ) > {
620
- for statement in block. statements . iter ( ) . rev ( ) {
621
- match & statement. kind {
622
- mir:: StatementKind :: Assign ( box ( lhs, mir:: Rvalue :: Discriminant ( discriminated) ) )
623
- if * lhs == switch_on =>
624
- {
625
- match discriminated. ty ( body, tcx) . ty . kind ( ) {
626
- ty:: Adt ( def, _) => return Some ( ( * discriminated, * def) ) ,
627
-
628
- // `Rvalue::Discriminant` is also used to get the active yield point for a
629
- // coroutine, but we do not need edge-specific effects in that case. This may
630
- // change in the future.
631
- ty:: Coroutine ( ..) => return None ,
632
-
633
- t => bug ! ( "`discriminant` called on unexpected type {:?}" , t) ,
634
- }
635
- }
636
- mir:: StatementKind :: Coverage ( _) => continue ,
637
- _ => return None ,
638
- }
639
- }
640
- None
641
- }
0 commit comments