Skip to content

Commit 881c62f

Browse files
committed
address review comments
1 parent ef82648 commit 881c62f

File tree

5 files changed

+84
-135
lines changed

5 files changed

+84
-135
lines changed

compiler/rustc_mir_dataflow/src/drop_flag_effects.rs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use rustc_abi::VariantIdx;
22
use rustc_middle::mir::{self, Body, Location, Terminator, TerminatorKind};
3+
use smallvec::SmallVec;
34
use tracing::debug;
45

56
use super::move_paths::{InitKind, LookupResult, MoveData, MovePathIndex};
@@ -155,15 +156,29 @@ where
155156
}
156157
}
157158

158-
/// Handles each variant that corresponds to one of the child move paths of `enum_place`. If the
159-
/// variant is `active_variant`, `handle_active_variant` will be called. Otherwise,
160-
/// `handle_inactive_variant` will be called.
161-
pub(crate) fn on_all_variants<'tcx>(
159+
/// Indicates which variants are inactive at a `SwitchInt` edge by listing their `VariantIdx`s or
160+
/// specifying the single active variant's `VariantIdx`.
161+
pub(crate) enum InactiveVariants {
162+
Inactives(SmallVec<[VariantIdx; 4]>),
163+
Active(VariantIdx),
164+
}
165+
166+
impl InactiveVariants {
167+
fn contains(&self, variant_idx: VariantIdx) -> bool {
168+
match self {
169+
InactiveVariants::Inactives(inactives) => inactives.contains(&variant_idx),
170+
InactiveVariants::Active(active) => variant_idx != *active,
171+
}
172+
}
173+
}
174+
175+
/// Calls `handle_inactive_variant` for each child move path of `enum_place` corresponding to an
176+
/// inactive variant at a particular `SwitchInt` edge.
177+
pub(crate) fn on_all_inactive_variants<'tcx>(
162178
move_data: &MoveData<'tcx>,
163179
enum_place: mir::Place<'tcx>,
164-
active_variant: VariantIdx,
180+
inactive_variants: &InactiveVariants,
165181
mut handle_inactive_variant: impl FnMut(MovePathIndex),
166-
mut handle_active_variant: impl FnMut(MovePathIndex),
167182
) {
168183
let LookupResult::Exact(enum_mpi) = move_data.rev_lookup.find(enum_place.as_ref()) else {
169184
return;
@@ -181,10 +196,8 @@ pub(crate) fn on_all_variants<'tcx>(
181196
unreachable!();
182197
};
183198

184-
if variant_idx != active_variant {
199+
if inactive_variants.contains(variant_idx) {
185200
on_all_children_bits(move_data, variant_mpi, |mpi| handle_inactive_variant(mpi));
186-
} else {
187-
on_all_children_bits(move_data, variant_mpi, |mpi| handle_active_variant(mpi));
188201
}
189202
}
190203
}

compiler/rustc_mir_dataflow/src/framework/direction.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use std::ops::RangeInclusive;
22

3-
use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges};
3+
use rustc_middle::mir::{
4+
self, BasicBlock, CallReturnPlaces, Location, SwitchTargetValue, TerminatorEdges,
5+
};
46

57
use super::visitor::ResultsVisitor;
68
use super::{Analysis, Effect, EffectIndex};
@@ -110,12 +112,13 @@ impl Direction for Backward {
110112
propagate(pred, &tmp);
111113
}
112114

113-
mir::TerminatorKind::SwitchInt { targets: _, ref discr } => {
115+
mir::TerminatorKind::SwitchInt { ref targets, ref discr } => {
114116
if let Some(mut data) = analysis.get_switch_int_data(block, discr) {
115117
let mut tmp = analysis.bottom_value(body);
116118
for &value in &body.basic_blocks.switch_sources()[&(block, pred)] {
117119
tmp.clone_from(exit_state);
118-
analysis.apply_switch_int_edge_effect(&mut data, &mut tmp, value, None);
120+
analysis
121+
.apply_switch_int_edge_effect(&mut data, &mut tmp, value, targets);
119122
propagate(pred, &tmp);
120123
}
121124
} else {
@@ -243,7 +246,7 @@ impl Direction for Forward {
243246

244247
fn apply_effects_in_block<'mir, 'tcx, A>(
245248
analysis: &mut A,
246-
_body: &mir::Body<'tcx>,
249+
body: &mir::Body<'tcx>,
247250
state: &mut A::Domain,
248251
block: BasicBlock,
249252
block_data: &'mir mir::BasicBlockData<'tcx>,
@@ -283,10 +286,25 @@ impl Direction for Forward {
283286
}
284287
}
285288
TerminatorEdges::SwitchInt { targets, discr } => {
286-
if let Some(data) = analysis.get_switch_int_data(block, discr) {
287-
analysis.apply_switch_int_edge_effect_for_targets(
288-
targets, data, exit_state, propagate,
289+
if let Some(mut data) = analysis.get_switch_int_data(block, discr) {
290+
let mut tmp = analysis.bottom_value(body);
291+
for (value, target) in targets.iter() {
292+
tmp.clone_from(exit_state);
293+
let value = SwitchTargetValue::Normal(value);
294+
analysis.apply_switch_int_edge_effect(&mut data, &mut tmp, value, targets);
295+
propagate(target, &tmp);
296+
}
297+
298+
// Once we get to the final, "otherwise" branch, there is no need to preserve
299+
// `exit_state`, so pass it directly to `apply_switch_int_edge_effect` to save
300+
// a clone of the dataflow state.
301+
analysis.apply_switch_int_edge_effect(
302+
&mut data,
303+
exit_state,
304+
SwitchTargetValue::Otherwise,
305+
targets,
289306
);
307+
propagate(targets.otherwise(), exit_state);
290308
} else {
291309
for target in targets.all_targets() {
292310
propagate(*target, exit_state);

compiler/rustc_mir_dataflow/src/framework/mod.rs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -224,20 +224,7 @@ pub trait Analysis<'tcx> {
224224
_data: &mut Self::SwitchIntData,
225225
_state: &mut Self::Domain,
226226
_value: SwitchTargetValue,
227-
_otherwise_state: Option<&mut Self::Domain>,
228-
) {
229-
unreachable!();
230-
}
231-
232-
/// Calls `apply_switch_int_edge_effect` for each target in `targets` and calls `propagate` with
233-
/// the new state. This is used in forward analysis for `MaybeUninitializedPlaces` and
234-
/// `MaybeInitializedPlaces`.
235-
fn apply_switch_int_edge_effect_for_targets(
236-
&mut self,
237227
_targets: &mir::SwitchTargets,
238-
mut _data: Self::SwitchIntData,
239-
_state: &mut Self::Domain,
240-
mut _propagate: impl FnMut(mir::BasicBlock, &Self::Domain),
241228
) {
242229
unreachable!();
243230
}

compiler/rustc_mir_dataflow/src/impls/initialized.rs

Lines changed: 34 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ use rustc_middle::mir::{
99
};
1010
use rustc_middle::ty::util::Discr;
1111
use rustc_middle::ty::{self, TyCtxt};
12+
use smallvec::SmallVec;
1213
use tracing::{debug, instrument};
1314

14-
use crate::drop_flag_effects::DropFlagState;
15+
use crate::drop_flag_effects::{DropFlagState, InactiveVariants};
1516
use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex};
1617
use crate::{
1718
Analysis, GenKill, MaybeReachable, drop_flag_effects, drop_flag_effects_for_function_entry,
@@ -26,6 +27,12 @@ pub struct MaybePlacesSwitchIntData<'tcx> {
2627
}
2728

2829
impl<'tcx> MaybePlacesSwitchIntData<'tcx> {
30+
/// Creates a `SmallVec` mapping each target in `targets` to its `VariantIdx`.
31+
fn variants(&mut self, targets: &mir::SwitchTargets) -> SmallVec<[VariantIdx; 4]> {
32+
self.index = 0;
33+
targets.all_values().iter().map(|value| self.next_discr(value.get())).collect()
34+
}
35+
2936
// The discriminant order in the `SwitchInt` targets should match the order yielded by
3037
// `AdtDef::discriminants`. We rely on this to match each discriminant in the targets to its
3138
// corresponding variant in linear time.
@@ -454,63 +461,24 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
454461
data: &mut Self::SwitchIntData,
455462
state: &mut Self::Domain,
456463
value: SwitchTargetValue,
457-
otherwise_state: Option<&mut Self::Domain>,
464+
targets: &mir::SwitchTargets,
458465
) {
459-
let SwitchTargetValue::Normal(value) = value else {
460-
return;
466+
let inactive_variants = match value {
467+
SwitchTargetValue::Normal(value) => InactiveVariants::Active(data.next_discr(value)),
468+
SwitchTargetValue::Otherwise if self.exclude_inactive_in_otherwise => {
469+
InactiveVariants::Inactives(data.variants(targets))
470+
}
471+
_ => return,
461472
};
462473

463-
let handle_inactive_variant = |mpi| state.kill(mpi);
464-
465474
// Kill all move paths that correspond to variants we know to be inactive along this
466475
// particular outgoing edge of a `SwitchInt`.
467-
match otherwise_state {
468-
Some(otherwise_state) => {
469-
drop_flag_effects::on_all_variants(
470-
self.move_data,
471-
data.enum_place,
472-
data.next_discr(value),
473-
handle_inactive_variant,
474-
|mpi| otherwise_state.kill(mpi),
475-
);
476-
}
477-
None => {
478-
drop_flag_effects::on_all_variants(
479-
self.move_data,
480-
data.enum_place,
481-
data.next_discr(value),
482-
handle_inactive_variant,
483-
|_mpi| {},
484-
);
485-
}
486-
}
487-
}
488-
489-
fn apply_switch_int_edge_effect_for_targets(
490-
&mut self,
491-
targets: &mir::SwitchTargets,
492-
mut data: Self::SwitchIntData,
493-
state: &mut Self::Domain,
494-
mut propagate: impl FnMut(mir::BasicBlock, &Self::Domain),
495-
) {
496-
let analyze_otherwise = self.exclude_inactive_in_otherwise
497-
&& (1..data.discriminants.len()).contains(&targets.all_values().len());
498-
499-
let mut otherwise_state = if analyze_otherwise { Some(state.clone()) } else { None };
500-
let mut target_state = MaybeReachable::Unreachable;
501-
502-
for (value, target) in targets.iter() {
503-
target_state.clone_from(&state);
504-
self.apply_switch_int_edge_effect(
505-
&mut data,
506-
&mut target_state,
507-
SwitchTargetValue::Normal(value),
508-
otherwise_state.as_mut(),
509-
);
510-
propagate(target, &target_state);
511-
}
512-
513-
propagate(targets.otherwise(), otherwise_state.as_ref().unwrap_or(state));
476+
drop_flag_effects::on_all_inactive_variants(
477+
self.move_data,
478+
data.enum_place,
479+
&inactive_variants,
480+
|mpi| state.kill(mpi),
481+
);
514482
}
515483
}
516484

@@ -613,63 +581,24 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
613581
data: &mut Self::SwitchIntData,
614582
state: &mut Self::Domain,
615583
value: SwitchTargetValue,
616-
otherwise_state: Option<&mut Self::Domain>,
584+
targets: &mir::SwitchTargets,
617585
) {
618-
let SwitchTargetValue::Normal(value) = value else {
619-
return;
586+
let inactive_variants = match value {
587+
SwitchTargetValue::Normal(value) => InactiveVariants::Active(data.next_discr(value)),
588+
SwitchTargetValue::Otherwise if self.include_inactive_in_otherwise => {
589+
InactiveVariants::Inactives(data.variants(targets))
590+
}
591+
_ => return,
620592
};
621593

622-
let handle_inactive_variant = |mpi| state.gen_(mpi);
623-
624594
// Mark all move paths that correspond to variants other than this one as maybe
625595
// uninitialized (in reality, they are *definitely* uninitialized).
626-
match otherwise_state {
627-
Some(otherwise_state) => {
628-
drop_flag_effects::on_all_variants(
629-
self.move_data,
630-
data.enum_place,
631-
data.next_discr(value),
632-
handle_inactive_variant,
633-
|mpi| otherwise_state.gen_(mpi),
634-
);
635-
}
636-
None => {
637-
drop_flag_effects::on_all_variants(
638-
self.move_data,
639-
data.enum_place,
640-
data.next_discr(value),
641-
handle_inactive_variant,
642-
|_mpi| {},
643-
);
644-
}
645-
}
646-
}
647-
648-
fn apply_switch_int_edge_effect_for_targets(
649-
&mut self,
650-
targets: &mir::SwitchTargets,
651-
mut data: Self::SwitchIntData,
652-
state: &mut Self::Domain,
653-
mut propagate: impl FnMut(mir::BasicBlock, &Self::Domain),
654-
) {
655-
let analyze_otherwise = self.include_inactive_in_otherwise
656-
&& (1..data.discriminants.len()).contains(&targets.all_values().len());
657-
658-
let mut otherwise_state = if analyze_otherwise { Some(state.clone()) } else { None };
659-
let mut target_state = MixedBitSet::new_empty(self.move_data().move_paths.len());
660-
661-
for (value, target) in targets.iter() {
662-
target_state.clone_from(&state);
663-
self.apply_switch_int_edge_effect(
664-
&mut data,
665-
&mut target_state,
666-
SwitchTargetValue::Normal(value),
667-
otherwise_state.as_mut(),
668-
);
669-
propagate(target, &target_state);
670-
}
671-
672-
propagate(targets.otherwise(), otherwise_state.as_ref().unwrap_or(state));
596+
drop_flag_effects::on_all_inactive_variants(
597+
self.move_data,
598+
data.enum_place,
599+
&inactive_variants,
600+
|mpi| state.gen_(mpi),
601+
);
673602
}
674603
}
675604

tests/mir-opt/otherwise_drops.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
// skip-filecheck
21
//@ test-mir-pass: ElaborateDrops
32

43
// Ensures there are no drops for the wildcard match arm.
54

65
// EMIT_MIR otherwise_drops.result_ok.ElaborateDrops.after.mir
76
fn result_ok(result: Result<String, ()>) -> Option<String> {
7+
// CHECK-LABEL: fn result_ok(
8+
// CHECK-NOT: drop
9+
// CHECK: return
810
match result {
911
Ok(s) => Some(s),
1012
_ => None,

0 commit comments

Comments
 (0)