Skip to content

Commit

Permalink
Replicate live variant drop elaboration during const-checking
Browse files Browse the repository at this point in the history
  • Loading branch information
ecstatic-morse committed Aug 29, 2020
1 parent c85779c commit 0819c05
Showing 1 changed file with 47 additions and 2 deletions.
49 changes: 47 additions & 2 deletions src/librustc_mir/transform/check_consts/post_drop_elaboration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ use super::ops;
use super::qualifs::{NeedsDrop, Qualif};
use super::validation::Qualifs;
use super::ConstCx;
use crate::dataflow::drop_flag_effects::on_all_drop_children_bits;
use crate::dataflow::move_paths::MoveData;
use crate::dataflow::{self, Analysis, MoveDataParamEnv, ResultsCursor};

/// Returns `true` if we should use the more precise live drop checker that runs after drop
/// elaboration.
Expand All @@ -31,14 +34,22 @@ pub fn check_live_drops(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &mir::Body<

let ccx = ConstCx { body, tcx, def_id, const_kind, param_env: tcx.param_env(def_id) };

let mut visitor = CheckLiveDrops { ccx: &ccx, qualifs: Qualifs::default() };
let mut visitor = CheckLiveDrops { ccx: &ccx, qualifs: Qualifs::default(), maybe_inits: None };

visitor.visit_body(body);
}

type MaybeInits<'mir, 'tcx> = ResultsCursor<
'mir,
'tcx,
dataflow::impls::MaybeInitializedPlaces<'mir, 'tcx, MoveDataParamEnv<'tcx>>,
>;

struct CheckLiveDrops<'mir, 'tcx> {
ccx: &'mir ConstCx<'mir, 'tcx>,
qualifs: Qualifs<'mir, 'tcx>,

maybe_inits: Option<MaybeInits<'mir, 'tcx>>,
}

// So we can access `body` and `tcx`.
Expand Down Expand Up @@ -83,7 +94,41 @@ impl Visitor<'tcx> for CheckLiveDrops<'mir, 'tcx> {
return;
}

if self.qualifs.needs_drop(self.ccx, dropped_place.local, location) {
if !self.qualifs.needs_drop(self.ccx, dropped_place.local, location) {
return;
}

let ConstCx { param_env, body, tcx, def_id, .. } = *self.ccx;

// Replicate some logic from drop elaboration during const-checking. If we know
// that the active variant of an enum does not have drop glue, we can allow it to
// be dropped.
let maybe_inits = self.maybe_inits.get_or_insert_with(|| {
let move_data = MoveData::gather_moves(body, tcx, param_env).unwrap();
let mdpe = MoveDataParamEnv { move_data, param_env };
dataflow::impls::MaybeInitializedPlaces::new(tcx, body, mdpe)
.mark_inactive_variants_as_uninit(true)
.into_engine(tcx, body, def_id.to_def_id())
.iterate_to_fixpoint()
.into_results_cursor(body)
});
maybe_inits.seek_before_primary_effect(location);
let mdpe = &maybe_inits.analysis().mdpe;

let dropped_mpi = mdpe
.move_data
.rev_lookup
.find(dropped_place.as_ref())
.expect_exact("All dropped places should have a move path");

let mut is_live_drop = false;
on_all_drop_children_bits(tcx, body, mdpe, dropped_mpi, |mpi| {
if maybe_inits.contains(mpi) {
is_live_drop = true;
}
});

if is_live_drop {
// Use the span where the dropped local was declared for the error.
let span = self.body.local_decls[dropped_place.local].source_info.span;
self.check_live_drop(span);
Expand Down

0 comments on commit 0819c05

Please sign in to comment.