From 915a581bcb3d9b7e1e2ef0da4fbfbae6b1a7fa7f Mon Sep 17 00:00:00 2001 From: Tomasz Miąsko Date: Sun, 17 Oct 2021 00:00:00 +0000 Subject: Do not promote values with const drop that need to be dropped Changes from #88558 allowed using `~const Drop` in constants by introducing a new `NeedsNonConstDrop` qualif. The new qualif was also used for promotion purposes, and allowed promotion to happen for values that needs to be dropped but which do have a const drop impl. Since for promoted the drop implementation is never executed, this lead to observable change in behaviour. For example: ```rust struct Panic(); impl const Drop for Panic { fn drop(&mut self) { panic!(); } } fn main() { let _ = &Panic(); } ``` Restore the use of `NeedsDrop` qualif during promotion to avoid the issue. --- .../src/transform/check_consts/check.rs | 31 +++++++++++++++++++++- .../src/transform/check_consts/qualifs.rs | 29 +++++++++++++++++--- .../src/transform/promote_consts.rs | 2 +- 3 files changed, 57 insertions(+), 5 deletions(-) (limited to 'compiler/rustc_const_eval') diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 8cd75dd8e28..03e60deea27 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -22,7 +22,7 @@ use std::mem; use std::ops::Deref; use super::ops::{self, NonConstOp, Status}; -use super::qualifs::{self, CustomEq, HasMutInterior, NeedsNonConstDrop}; +use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop, NeedsNonConstDrop}; use super::resolver::FlowSensitiveAnalysis; use super::{is_lang_panic_fn, is_lang_special_const_fn, ConstCx, Qualif}; use crate::const_eval::is_unstable_const_fn; @@ -39,6 +39,7 @@ type QualifResults<'mir, 'tcx, Q> = #[derive(Default)] pub struct Qualifs<'mir, 'tcx> { has_mut_interior: Option>, + needs_drop: Option>, needs_non_const_drop: Option>, indirectly_mutable: Option>, } @@ -70,6 +71,33 @@ impl Qualifs<'mir, 'tcx> { indirectly_mutable.get().contains(local) } + /// Returns `true` if `local` is `NeedsDrop` at the given `Location`. + /// + /// Only updates the cursor if absolutely necessary + pub fn needs_drop( + &mut self, + ccx: &'mir ConstCx<'mir, 'tcx>, + local: Local, + location: Location, + ) -> bool { + let ty = ccx.body.local_decls[local].ty; + if !NeedsDrop::in_any_value_of_ty(ccx, ty) { + return false; + } + + let needs_drop = self.needs_drop.get_or_insert_with(|| { + let ConstCx { tcx, body, .. } = *ccx; + + FlowSensitiveAnalysis::new(NeedsDrop, ccx) + .into_engine(tcx, &body) + .iterate_to_fixpoint() + .into_results_cursor(&body) + }); + + needs_drop.seek_before_primary_effect(location); + needs_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location) + } + /// Returns `true` if `local` is `NeedsNonConstDrop` at the given `Location`. /// /// Only updates the cursor if absolutely necessary @@ -172,6 +200,7 @@ impl Qualifs<'mir, 'tcx> { }; ConstQualifs { + needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc), needs_non_const_drop: self.needs_non_const_drop(ccx, RETURN_PLACE, return_loc), has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc), custom_eq, diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 689aa099371..dd2980d40ad 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -21,6 +21,7 @@ pub fn in_any_value_of_ty( ) -> ConstQualifs { ConstQualifs { has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty), + needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty), needs_non_const_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty), custom_eq: CustomEq::in_any_value_of_ty(cx, ty), error_occured, @@ -98,9 +99,31 @@ impl Qualif for HasMutInterior { } /// Constant containing an ADT that implements `Drop`. -/// This must be ruled out (a) because we cannot run `Drop` during compile-time -/// as that might not be a `const fn`, and (b) because implicit promotion would -/// remove side-effects that occur as part of dropping that value. +/// This must be ruled out because implicit promotion would remove side-effects +/// that occur as part of dropping that value. N.B., the implicit promotion has +/// to reject const Drop implementations because even if side-effects are ruled +/// out through other means, the execution of the drop could diverge. +pub struct NeedsDrop; + +impl Qualif for NeedsDrop { + const ANALYSIS_NAME: &'static str = "flow_needs_drop"; + const IS_CLEARED_ON_MOVE: bool = true; + + fn in_qualifs(qualifs: &ConstQualifs) -> bool { + qualifs.needs_drop + } + + fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { + ty.needs_drop(cx.tcx, cx.param_env) + } + + fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool { + adt.has_dtor(cx.tcx) + } +} + +/// Constant containing an ADT that implements non-const `Drop`. +/// This must be ruled out because we cannot run `Drop` during compile-time. pub struct NeedsNonConstDrop; impl Qualif for NeedsNonConstDrop { diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 7cfe3d7f809..ebcc8213c60 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -230,7 +230,7 @@ impl<'tcx> Validator<'_, 'tcx> { // We cannot promote things that need dropping, since the promoted value // would not get dropped. - if self.qualif_local::(place.local) { + if self.qualif_local::(place.local) { return Err(Unpromotable); } -- cgit 1.4.1-3-g733a5