From d94a9019b2c433288209d65d1831646406e527be Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 4 Sep 2019 11:17:09 -0700 Subject: [PATCH] Implement a non-dataflow, temp-only `Qualif` resolver --- src/librustc_mir/transform/qualify_consts.rs | 144 +++++++++++++++---- 1 file changed, 114 insertions(+), 30 deletions(-) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 145a4b0f79fff..a9d0c3768ead8 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -697,16 +697,16 @@ macro_rules! define_qualifs { ( $( $Q:ident, $field:ident );* $(;)? ) => { $( impl Index<$Q> for Resolvers<'mir, 'tcx> { - type Output = FlowSensitiveResolver<'mir, 'tcx, $Q>; + type Output = dyn 'mir + QualifResolver<'tcx, $Q>; fn index(&self, _: $Q) -> &Self::Output { - &self.$field + &*self.$field } } impl IndexMut<$Q> for Resolvers<'mir, 'tcx> { fn index_mut(&mut self, _: $Q) -> &mut Self::Output { - &mut self.$field + &mut *self.$field } } )* @@ -840,10 +840,10 @@ trait QualifResolver<'tcx, Q>: Visitor<'tcx> { /// `resolvers[NeedsDrop]`). This chicanery makes the use of macros like `for_each_qualif` more /// convenient. pub struct Resolvers<'mir, 'tcx> { - needs_drop: FlowSensitiveResolver<'mir, 'tcx, NeedsDrop>, - has_mut_interior: FlowSensitiveResolver<'mir, 'tcx, HasMutInterior>, - is_not_promotable: FlowSensitiveResolver<'mir, 'tcx, IsNotPromotable>, - is_not_implicitly_promotable: FlowSensitiveResolver<'mir, 'tcx, IsNotImplicitlyPromotable>, + needs_drop: Box>, + has_mut_interior: Box>, + is_not_promotable: Box>, + is_not_implicitly_promotable: Box>, } impl Resolvers<'mir, 'tcx> { @@ -867,34 +867,52 @@ impl Resolvers<'mir, 'tcx> { let borrowed_locals = dataflow::DataflowResultsCursor::new(borrowed_locals, cx.body); let borrowed_locals = Rc::new(RefCell::new(borrowed_locals)); - let needs_drop = FlowSensitiveResolver::new( - NeedsDrop, - cx, - borrowed_locals.clone(), - temp_promotion_state, - &dead_unwinds, - ); - let has_mut_interior = FlowSensitiveResolver::new( - HasMutInterior, - cx, - borrowed_locals.clone(), - temp_promotion_state, - &dead_unwinds, - ); - let is_not_promotable = FlowSensitiveResolver::new( + let needs_drop = if cx.mode == Mode::NonConstFn { + Box::new(TempOnlyResolver::new( + NeedsDrop, + cx, + borrowed_locals.clone(), + temp_promotion_state, + )) as Box<_> + } else { + Box::new(FlowSensitiveResolver::new( + NeedsDrop, + cx, + borrowed_locals.clone(), + temp_promotion_state, + &dead_unwinds, + )) as Box<_> + }; + + let has_mut_interior = if cx.mode == Mode::NonConstFn { + Box::new(TempOnlyResolver::new( + HasMutInterior, + cx, + borrowed_locals.clone(), + temp_promotion_state, + )) as Box<_> + } else { + Box::new(FlowSensitiveResolver::new( + HasMutInterior, + cx, + borrowed_locals.clone(), + temp_promotion_state, + &dead_unwinds, + )) as Box<_> + }; + + let is_not_promotable = Box::new(TempOnlyResolver::new( IsNotPromotable, cx, borrowed_locals.clone(), temp_promotion_state, - &dead_unwinds, - ); - let is_not_implicitly_promotable = FlowSensitiveResolver::new( + )); + let is_not_implicitly_promotable = Box::new(TempOnlyResolver::new( IsNotImplicitlyPromotable, cx, borrowed_locals.clone(), temp_promotion_state, - &dead_unwinds, - ); + )); Resolvers { needs_drop, @@ -905,6 +923,72 @@ impl Resolvers<'mir, 'tcx> { } } +struct TempOnlyResolver<'mir, 'tcx, Q> { + cx: ConstCx<'mir, 'tcx>, + borrowed_locals: BorrowedLocalsResults<'mir, 'tcx>, + per_local: BitSet, + _qualif: PhantomData, +} + +impl TempOnlyResolver<'mir, 'tcx, Q> +where + Q: Qualif, +{ + fn new( + _: Q, + cx: &ConstCx<'mir, 'tcx>, + borrowed_locals: BorrowedLocalsResults<'mir, 'tcx>, + temp_promotion_state: &IndexVec, + ) -> Self { + let mut per_local = BitSet::new_empty(cx.body.local_decls.len()); + initialize_qualifs::(&mut per_local, cx, temp_promotion_state); + + TempOnlyResolver { + cx: (*cx).clone(), + borrowed_locals, + per_local, + _qualif: PhantomData, + } + } +} + + +impl Visitor<'tcx> for TempOnlyResolver<'_, 'tcx, Q> +where + Q: Qualif +{ + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + QualifPropagator::::new(&self.cx, &mut self.per_local, &self.borrowed_locals) + .visit_statement(statement, location); + } + + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + QualifPropagator::::new(&self.cx, &mut self.per_local, &self.borrowed_locals) + .visit_terminator(terminator, location); + + if let mir::TerminatorKind::Call { + destination: Some((return_place, _)), + func, + args, + .. + } = &terminator.kind { + let return_ty = return_place.ty(self.cx.body, self.cx.tcx).ty; + let in_call = Q::in_call(&self.cx, &mut self.per_local, func, args, return_ty); + QualifPropagator::::new(&self.cx, &mut self.per_local, &self.borrowed_locals) + .assign_qualif(return_place, in_call, location); + } + } +} + +impl QualifResolver<'tcx, Q> for TempOnlyResolver<'_, 'tcx, Q> +where + Q: Qualif +{ + fn get(&mut self) -> &BitSet { + &self.per_local + } +} + struct FlowSensitiveResolver<'mir, 'tcx, Q> where Q: Qualif @@ -1116,9 +1200,8 @@ where borrowed_locals.seek(location); for local in borrowed_locals.get().iter() { - // FIXME: This is unsound. Mutable borrows can still mutate types that aren't `Freeze`. let ty = self.cx.body.local_decls[local].ty; - if !ty.is_freeze(self.cx.tcx, self.cx.param_env, DUMMY_SP) { + if Q::in_any_value_of_ty(&self.cx, ty).unwrap_or(true) { self.qualifs_per_local.insert(local); } } @@ -2220,7 +2303,8 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> (u8, &BitSet) { return (1 << IsNotPromotable::IDX, tcx.arena.alloc(BitSet::new_empty(0))); } - Checker::new(tcx, def_id, body, Mode::Const).check_const() + let mut checker = Checker::new(tcx, def_id, body, Mode::Const); + checker.check_const() } pub struct QualifyAndPromoteConstants<'tcx> {