Skip to content

Commit ca8678b

Browse files
Handle inactive enum variants in MaybeUninitializedPlaces
1 parent 0ca7f74 commit ca8678b

File tree

3 files changed

+89
-23
lines changed

3 files changed

+89
-23
lines changed

src/librustc_mir/dataflow/drop_flag_effects.rs

+40
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::util::elaborate_drops::DropFlagState;
22
use rustc_middle::mir::{self, Body, Location};
33
use rustc_middle::ty::{self, TyCtxt};
4+
use rustc_target::abi::VariantIdx;
45

56
use super::indexes::MovePathIndex;
67
use super::move_paths::{InitKind, LookupResult, MoveData};
@@ -228,3 +229,42 @@ pub(crate) fn for_location_inits<'tcx, F>(
228229
}
229230
}
230231
}
232+
233+
/// Calls `handle_inactive_variant` for each descendant move path of `enum_place` that contains a
234+
/// `Downcast` to a variant besides the `active_variant`.
235+
///
236+
/// NOTE: If there are no move paths corresponding to an inactive variant,
237+
/// `handle_inactive_variant` will not be called for that variant.
238+
pub(crate) fn on_all_inactive_variants<'tcx>(
239+
tcx: TyCtxt<'tcx>,
240+
body: &mir::Body<'tcx>,
241+
move_data: &MoveData<'tcx>,
242+
enum_place: mir::Place<'tcx>,
243+
active_variant: VariantIdx,
244+
mut handle_inactive_variant: impl FnMut(MovePathIndex),
245+
) {
246+
let enum_mpi = match move_data.rev_lookup.find(enum_place.as_ref()) {
247+
LookupResult::Exact(mpi) => mpi,
248+
LookupResult::Parent(_) => return,
249+
};
250+
251+
let enum_path = &move_data.move_paths[enum_mpi];
252+
for (variant_mpi, variant_path) in enum_path.children(&move_data.move_paths) {
253+
// Because of the way we build the `MoveData` tree, each child should have exactly one more
254+
// projection than `enum_place`. This additional projection must be a downcast since the
255+
// base is an enum.
256+
let (downcast, base_proj) = variant_path.place.projection.split_last().unwrap();
257+
assert_eq!(enum_place.projection.len(), base_proj.len());
258+
259+
let variant_idx = match *downcast {
260+
mir::ProjectionElem::Downcast(_, idx) => idx,
261+
_ => unreachable!(),
262+
};
263+
264+
if variant_idx != active_variant {
265+
on_all_children_bits(tcx, body, move_data, variant_mpi, |mpi| {
266+
handle_inactive_variant(mpi)
267+
});
268+
}
269+
}
270+
}

src/librustc_mir/dataflow/impls/mod.rs

+48-23
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use super::MoveDataParamEnv;
1212

1313
use crate::util::elaborate_drops::DropFlagState;
1414

15-
use super::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex};
15+
use super::move_paths::{HasMoveData, InitIndex, InitKind, MoveData, MovePathIndex};
1616
use super::{AnalysisDomain, BottomValue, GenKill, GenKillAnalysis};
1717

1818
use super::drop_flag_effects_for_function_entry;
@@ -124,11 +124,23 @@ pub struct MaybeUninitializedPlaces<'a, 'tcx> {
124124
tcx: TyCtxt<'tcx>,
125125
body: &'a Body<'tcx>,
126126
mdpe: &'a MoveDataParamEnv<'tcx>,
127+
128+
mark_inactive_variants_as_uninit: bool,
127129
}
128130

129131
impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> {
130132
pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self {
131-
MaybeUninitializedPlaces { tcx, body, mdpe }
133+
MaybeUninitializedPlaces { tcx, body, mdpe, mark_inactive_variants_as_uninit: false }
134+
}
135+
136+
/// Causes inactive enum variants to be marked as "maybe uninitialized" after a switch on an
137+
/// enum discriminant.
138+
///
139+
/// This is correct in a vacuum but is not the default because it causes problems in the borrow
140+
/// checker, where this information gets propagated along `FakeEdge`s.
141+
pub fn mark_inactive_variants_as_uninit(mut self) -> Self {
142+
self.mark_inactive_variants_as_uninit = true;
143+
self
132144
}
133145
}
134146

@@ -350,27 +362,16 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
350362
_adt: &ty::AdtDef,
351363
variant: VariantIdx,
352364
) {
353-
let enum_mpi = match self.move_data().rev_lookup.find(enum_place.as_ref()) {
354-
LookupResult::Exact(mpi) => mpi,
355-
LookupResult::Parent(_) => return,
356-
};
357-
358-
// Kill all move paths that correspond to variants other than this one
359-
let move_paths = &self.move_data().move_paths;
360-
let enum_path = &move_paths[enum_mpi];
361-
for (mpi, variant_path) in enum_path.children(move_paths) {
362-
trans.kill(mpi);
363-
match variant_path.place.projection.last().unwrap() {
364-
mir::ProjectionElem::Downcast(_, idx) if *idx == variant => continue,
365-
_ => drop_flag_effects::on_all_children_bits(
366-
self.tcx,
367-
self.body,
368-
self.move_data(),
369-
mpi,
370-
|mpi| trans.kill(mpi),
371-
),
372-
}
373-
}
365+
// Kill all move paths that correspond to variants we know to be inactive along this
366+
// particular outgoing edge of a `SwitchInt`.
367+
drop_flag_effects::on_all_inactive_variants(
368+
self.tcx,
369+
self.body,
370+
self.move_data(),
371+
enum_place,
372+
variant,
373+
|mpi| trans.kill(mpi),
374+
);
374375
}
375376
}
376377

@@ -443,6 +444,30 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
443444
},
444445
);
445446
}
447+
448+
fn discriminant_switch_effect(
449+
&self,
450+
trans: &mut impl GenKill<Self::Idx>,
451+
_block: mir::BasicBlock,
452+
enum_place: mir::Place<'tcx>,
453+
_adt: &ty::AdtDef,
454+
variant: VariantIdx,
455+
) {
456+
if !self.mark_inactive_variants_as_uninit {
457+
return;
458+
}
459+
460+
// Mark all move paths that correspond to variants other than this one as maybe
461+
// uninitialized (in reality, they are *definitely* uninitialized).
462+
drop_flag_effects::on_all_inactive_variants(
463+
self.tcx,
464+
self.body,
465+
self.move_data(),
466+
enum_place,
467+
variant,
468+
|mpi| trans.gen(mpi),
469+
);
470+
}
446471
}
447472

448473
impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {

src/librustc_mir/transform/elaborate_drops.rs

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
4848
.into_results_cursor(body);
4949

5050
let uninits = MaybeUninitializedPlaces::new(tcx, body, &env)
51+
.mark_inactive_variants_as_uninit()
5152
.into_engine(tcx, body, def_id)
5253
.dead_unwinds(&dead_unwinds)
5354
.iterate_to_fixpoint()

0 commit comments

Comments
 (0)