Skip to content

Commit 4cc04f3

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

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.
@@ -428,15 +479,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
428479
return None;
429480
}
430481

431-
discr.place().and_then(|discr| {
432-
switch_on_enum_discriminant(self.tcx, self.body, &self.body[block], discr).map(
433-
|(enum_place, enum_def)| MaybePlacesSwitchIntData {
434-
enum_place,
435-
discriminants: enum_def.discriminants(self.tcx).collect(),
436-
index: 0,
437-
},
438-
)
439-
})
482+
MaybePlacesSwitchIntData::new(self.tcx, self.body, block, discr)
440483
}
441484

442485
fn apply_switch_int_edge_effect(
@@ -547,15 +590,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
547590
return None;
548591
}
549592

550-
discr.place().and_then(|discr| {
551-
switch_on_enum_discriminant(self.tcx, self.body, &self.body[block], discr).map(
552-
|(enum_place, enum_def)| MaybePlacesSwitchIntData {
553-
enum_place,
554-
discriminants: enum_def.discriminants(self.tcx).collect(),
555-
index: 0,
556-
},
557-
)
558-
})
593+
MaybePlacesSwitchIntData::new(self.tcx, self.body, block, discr)
559594
}
560595

561596
fn apply_switch_int_edge_effect(
@@ -725,45 +760,3 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
725760
}
726761
}
727762
}
728-
729-
/// Inspect a `SwitchInt`-terminated basic block to see if the condition of that `SwitchInt` is
730-
/// an enum discriminant.
731-
///
732-
/// We expect such blocks to have a call to `discriminant` as their last statement like so:
733-
///
734-
/// ```text
735-
/// ...
736-
/// _42 = discriminant(_1)
737-
/// SwitchInt(_42, ..)
738-
/// ```
739-
///
740-
/// If the basic block matches this pattern, this function returns the place corresponding to the
741-
/// enum (`_1` in the example above) as well as the `AdtDef` of that enum.
742-
fn switch_on_enum_discriminant<'mir, 'tcx>(
743-
tcx: TyCtxt<'tcx>,
744-
body: &'mir mir::Body<'tcx>,
745-
block: &'mir mir::BasicBlockData<'tcx>,
746-
switch_on: mir::Place<'tcx>,
747-
) -> Option<(mir::Place<'tcx>, ty::AdtDef<'tcx>)> {
748-
for statement in block.statements.iter().rev() {
749-
match &statement.kind {
750-
mir::StatementKind::Assign(box (lhs, mir::Rvalue::Discriminant(discriminated)))
751-
if *lhs == switch_on =>
752-
{
753-
match discriminated.ty(body, tcx).ty.kind() {
754-
ty::Adt(def, _) => return Some((*discriminated, *def)),
755-
756-
// `Rvalue::Discriminant` is also used to get the active yield point for a
757-
// coroutine, but we do not need edge-specific effects in that case. This may
758-
// change in the future.
759-
ty::Coroutine(..) => return None,
760-
761-
t => bug!("`discriminant` called on unexpected type {:?}", t),
762-
}
763-
}
764-
mir::StatementKind::Coverage(_) => continue,
765-
_ => return None,
766-
}
767-
}
768-
None
769-
}

0 commit comments

Comments
 (0)