Skip to content

Commit 2364b58

Browse files
Update dataflow impls to reflect new interface
1 parent 43e6ef8 commit 2364b58

File tree

1 file changed

+116
-33
lines changed
  • compiler/rustc_mir/src/dataflow/impls

1 file changed

+116
-33
lines changed

compiler/rustc_mir/src/dataflow/impls/mod.rs

+116-33
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use rustc_index::bit_set::BitSet;
66
use rustc_index::vec::Idx;
77
use rustc_middle::mir::{self, Body, Location};
88
use rustc_middle::ty::{self, TyCtxt};
9-
use rustc_target::abi::VariantIdx;
109

1110
use super::MoveDataParamEnv;
1211

@@ -19,6 +18,7 @@ use super::drop_flag_effects_for_function_entry;
1918
use super::drop_flag_effects_for_location;
2019
use super::on_lookup_result_bits;
2120
use crate::dataflow::drop_flag_effects;
21+
use crate::dataflow::framework::SwitchIntEdgeEffects;
2222

2323
mod borrowed_locals;
2424
pub(super) mod borrows;
@@ -352,24 +352,46 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
352352
);
353353
}
354354

355-
fn discriminant_switch_effect(
355+
fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
356356
&self,
357-
trans: &mut impl GenKill<Self::Idx>,
358-
_block: mir::BasicBlock,
359-
enum_place: mir::Place<'tcx>,
360-
_adt: &ty::AdtDef,
361-
variant: VariantIdx,
357+
block: mir::BasicBlock,
358+
discr: &mir::Operand<'tcx>,
359+
edge_effects: &mut impl SwitchIntEdgeEffects<G>,
362360
) {
363-
// Kill all move paths that correspond to variants we know to be inactive along this
364-
// particular outgoing edge of a `SwitchInt`.
365-
drop_flag_effects::on_all_inactive_variants(
366-
self.tcx,
367-
self.body,
368-
self.move_data(),
369-
enum_place,
370-
variant,
371-
|mpi| trans.kill(mpi),
372-
);
361+
let enum_ = discr.place().and_then(|discr| {
362+
switch_on_enum_discriminant(self.tcx, &self.body, &self.body[block], discr)
363+
});
364+
365+
let (enum_place, enum_def) = match enum_ {
366+
Some(x) => x,
367+
None => return,
368+
};
369+
370+
let mut discriminants = enum_def.discriminants(self.tcx);
371+
edge_effects.apply(|trans, edge| {
372+
let value = match edge.value {
373+
Some(x) => x,
374+
None => return,
375+
};
376+
377+
// MIR building adds discriminants to the `values` array in the same order as they
378+
// are yielded by `AdtDef::discriminants`. We rely on this to match each
379+
// discriminant in `values` to its corresponding variant in linear time.
380+
let (variant, _) = discriminants
381+
.find(|&(_, discr)| discr.val == value)
382+
.expect("Order of `AdtDef::discriminants` differed from `SwitchInt::values`");
383+
384+
// Kill all move paths that correspond to variants we know to be inactive along this
385+
// particular outgoing edge of a `SwitchInt`.
386+
drop_flag_effects::on_all_inactive_variants(
387+
self.tcx,
388+
self.body,
389+
self.move_data(),
390+
enum_place,
391+
variant,
392+
|mpi| trans.kill(mpi),
393+
);
394+
});
373395
}
374396
}
375397

@@ -441,28 +463,50 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
441463
);
442464
}
443465

444-
fn discriminant_switch_effect(
466+
fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
445467
&self,
446-
trans: &mut impl GenKill<Self::Idx>,
447-
_block: mir::BasicBlock,
448-
enum_place: mir::Place<'tcx>,
449-
_adt: &ty::AdtDef,
450-
variant: VariantIdx,
468+
block: mir::BasicBlock,
469+
discr: &mir::Operand<'tcx>,
470+
edge_effects: &mut impl SwitchIntEdgeEffects<G>,
451471
) {
452472
if !self.mark_inactive_variants_as_uninit {
453473
return;
454474
}
455475

456-
// Mark all move paths that correspond to variants other than this one as maybe
457-
// uninitialized (in reality, they are *definitely* uninitialized).
458-
drop_flag_effects::on_all_inactive_variants(
459-
self.tcx,
460-
self.body,
461-
self.move_data(),
462-
enum_place,
463-
variant,
464-
|mpi| trans.gen(mpi),
465-
);
476+
let enum_ = discr.place().and_then(|discr| {
477+
switch_on_enum_discriminant(self.tcx, &self.body, &self.body[block], discr)
478+
});
479+
480+
let (enum_place, enum_def) = match enum_ {
481+
Some(x) => x,
482+
None => return,
483+
};
484+
485+
let mut discriminants = enum_def.discriminants(self.tcx);
486+
edge_effects.apply(|trans, edge| {
487+
let value = match edge.value {
488+
Some(x) => x,
489+
None => return,
490+
};
491+
492+
// MIR building adds discriminants to the `values` array in the same order as they
493+
// are yielded by `AdtDef::discriminants`. We rely on this to match each
494+
// discriminant in `values` to its corresponding variant in linear time.
495+
let (variant, _) = discriminants
496+
.find(|&(_, discr)| discr.val == value)
497+
.expect("Order of `AdtDef::discriminants` differed from `SwitchInt::values`");
498+
499+
// Mark all move paths that correspond to variants other than this one as maybe
500+
// uninitialized (in reality, they are *definitely* uninitialized).
501+
drop_flag_effects::on_all_inactive_variants(
502+
self.tcx,
503+
self.body,
504+
self.move_data(),
505+
enum_place,
506+
variant,
507+
|mpi| trans.gen(mpi),
508+
);
509+
});
466510
}
467511
}
468512

@@ -624,3 +668,42 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
624668
}
625669
}
626670
}
671+
672+
/// Inspect a `SwitchInt`-terminated basic block to see if the condition of that `SwitchInt` is
673+
/// an enum discriminant.
674+
///
675+
/// We expect such blocks to have a call to `discriminant` as their last statement like so:
676+
///
677+
/// ```text
678+
/// ...
679+
/// _42 = discriminant(_1)
680+
/// SwitchInt(_42, ..)
681+
/// ```
682+
///
683+
/// If the basic block matches this pattern, this function returns the place corresponding to the
684+
/// enum (`_1` in the example above) as well as the `AdtDef` of that enum.
685+
fn switch_on_enum_discriminant(
686+
tcx: TyCtxt<'tcx>,
687+
body: &'mir mir::Body<'tcx>,
688+
block: &'mir mir::BasicBlockData<'tcx>,
689+
switch_on: mir::Place<'tcx>,
690+
) -> Option<(mir::Place<'tcx>, &'tcx ty::AdtDef)> {
691+
match block.statements.last().map(|stmt| &stmt.kind) {
692+
Some(mir::StatementKind::Assign(box (lhs, mir::Rvalue::Discriminant(discriminated))))
693+
if *lhs == switch_on =>
694+
{
695+
match &discriminated.ty(body, tcx).ty.kind() {
696+
ty::Adt(def, _) => Some((*discriminated, def)),
697+
698+
// `Rvalue::Discriminant` is also used to get the active yield point for a
699+
// generator, but we do not need edge-specific effects in that case. This may
700+
// change in the future.
701+
ty::Generator(..) => None,
702+
703+
t => bug!("`discriminant` called on unexpected type {:?}", t),
704+
}
705+
}
706+
707+
_ => None,
708+
}
709+
}

0 commit comments

Comments
 (0)