Skip to content

Commit c8c50f4

Browse files
committed
Factor out some shared code from Maybe{In,Unin}itializedPlaces.
1 parent 4d8316f commit c8c50f4

File tree

1 file changed

+53
-60
lines changed

1 file changed

+53
-60
lines changed

compiler/rustc_mir_dataflow/src/impls/initialized.rs

+53-60
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,57 @@ impl<'tcx> MaybePlacesSwitchIntData<'tcx> {
4040
}
4141
}
4242

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+
4394
/// `MaybeInitializedPlaces` tracks all places that might be
4495
/// initialized upon reaching a particular point in the control flow
4596
/// for a function.
@@ -364,15 +415,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
364415
return None;
365416
}
366417

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)
376419
}
377420

378421
fn apply_switch_int_edge_effect(
@@ -485,15 +528,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
485528
return None;
486529
}
487530

488-
discr.place().and_then(|discr| {
489-
switch_on_enum_discriminant(self.tcx, self.body, &self.body[block], discr).map(
490-
|(enum_place, enum_def)| MaybePlacesSwitchIntData {
491-
enum_place,
492-
discriminants: enum_def.discriminants(self.tcx).collect(),
493-
index: 0,
494-
},
495-
)
496-
})
531+
MaybePlacesSwitchIntData::new(self.tcx, self.body, block, discr)
497532
}
498533

499534
fn apply_switch_int_edge_effect(
@@ -601,45 +636,3 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
601636
}
602637
}
603638
}
604-
605-
/// Inspect a `SwitchInt`-terminated basic block to see if the condition of that `SwitchInt` is
606-
/// an enum discriminant.
607-
///
608-
/// We expect such blocks to have a call to `discriminant` as their last statement like so:
609-
///
610-
/// ```text
611-
/// ...
612-
/// _42 = discriminant(_1)
613-
/// SwitchInt(_42, ..)
614-
/// ```
615-
///
616-
/// If the basic block matches this pattern, this function returns the place corresponding to the
617-
/// enum (`_1` in the example above) as well as the `AdtDef` of that enum.
618-
fn switch_on_enum_discriminant<'mir, 'tcx>(
619-
tcx: TyCtxt<'tcx>,
620-
body: &'mir mir::Body<'tcx>,
621-
block: &'mir mir::BasicBlockData<'tcx>,
622-
switch_on: mir::Place<'tcx>,
623-
) -> Option<(mir::Place<'tcx>, ty::AdtDef<'tcx>)> {
624-
for statement in block.statements.iter().rev() {
625-
match &statement.kind {
626-
mir::StatementKind::Assign(box (lhs, mir::Rvalue::Discriminant(discriminated)))
627-
if *lhs == switch_on =>
628-
{
629-
match discriminated.ty(body, tcx).ty.kind() {
630-
ty::Adt(def, _) => return Some((*discriminated, *def)),
631-
632-
// `Rvalue::Discriminant` is also used to get the active yield point for a
633-
// coroutine, but we do not need edge-specific effects in that case. This may
634-
// change in the future.
635-
ty::Coroutine(..) => return None,
636-
637-
t => bug!("`discriminant` called on unexpected type {:?}", t),
638-
}
639-
}
640-
mir::StatementKind::Coverage(_) => continue,
641-
_ => return None,
642-
}
643-
}
644-
None
645-
}

0 commit comments

Comments
 (0)