Skip to content

Commit 6e4ad2c

Browse files
committed
Factor out some shared code from Maybe{In,Unin}itializedPlaces.
1 parent 21107e0 commit 6e4ad2c

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(
@@ -483,15 +526,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
483526
return None;
484527
}
485528

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)
495530
}
496531

497532
fn apply_switch_int_edge_effect(
@@ -597,45 +632,3 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
597632
}
598633
}
599634
}
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

Comments
 (0)