From 0819c05fc97127a1264ee994ca4865c28ed6a956 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 29 Aug 2020 12:28:36 -0700 Subject: [PATCH] Replicate live variant drop elaboration during const-checking --- .../check_consts/post_drop_elaboration.rs | 49 ++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs b/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs index 55075b3ab5e99..60767abbf3eb3 100644 --- a/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs +++ b/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs @@ -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. @@ -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>, } // So we can access `body` and `tcx`. @@ -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);