diff options
| author | bors <bors@rust-lang.org> | 2021-09-15 03:51:03 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2021-09-15 03:51:03 +0000 |
| commit | cdeba02ff71416e014f7130f75166890688be986 (patch) | |
| tree | 7abdff0663fd163ce1684276436982235b47f082 /compiler/rustc_const_eval/src/transform | |
| parent | c3c0f80d6081092faff801542dd82f0e2420152b (diff) | |
| parent | f749e05f6b95b66485c0417996d9aeb369def8da (diff) | |
| download | rust-cdeba02ff71416e014f7130f75166890688be986.tar.gz rust-cdeba02ff71416e014f7130f75166890688be986.zip | |
Auto merge of #88558 - fee1-dead:const-drop, r=oli-obk
Const drop
The changes are pretty primitive at this point. But at least it works. ^-^
Problems with the current change that I can think of now:
- [x] `~const Drop` shouldn't change anything in the non-const world.
- [x] types that do not have drop glues shouldn't fail to satisfy `~const Drop` in const contexts. `struct S { a: u8, b: u16 }` This might not fail for `needs_non_const_drop`, but it will fail in `rustc_trait_selection`.
- [x] The current change accepts types that have `const Drop` impls but have non-const `Drop` glue.
Fixes #88424.
Significant Changes:
- `~const Drop` is no longer treated as a normal trait bound. In non-const contexts, this bound has no effect, but in const contexts, this restricts the input type and all of its transitive fields to either a) have a `const Drop` impl or b) can be trivially dropped (i.e. no drop glue)
- `T: ~const Drop` will not be linted like `T: Drop`.
- Instead of recursing and iterating through the type in `rustc_mir::transform::check_consts`, we use the trait system to special case `~const Drop`. See [`rustc_trait_selection::...::candidate_assembly#assemble_const_drop_candidates`](https://github.com/fee1-dead/rust/blob/const-drop/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs#L817) and others.
Changes not related to `const Drop`ping and/or changes that are insignificant:
- `Node.constness_for_typeck` no longer returns `hir::Constness::Const` for type aliases in traits. This was previously used to hack how we determine default bound constness for items. But because we now use an explicit opt-in, it is no longer needed.
- Removed `is_const_impl_raw` query. We have `impl_constness`, and the only existing use of that query uses `HirId`, which means we can just operate it with hir.
- `ty::Destructor` now has a field `constness`, which represents the constness of the destructor.
r? `@oli-obk`
Diffstat (limited to 'compiler/rustc_const_eval/src/transform')
4 files changed, 52 insertions, 22 deletions
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 02b317b8981..d5682f702ba 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, NeedsDrop}; +use super::qualifs::{self, CustomEq, HasMutInterior, NeedsNonConstDrop}; use super::resolver::FlowSensitiveAnalysis; use super::{is_lang_panic_fn, ConstCx, Qualif}; use crate::const_eval::is_unstable_const_fn; @@ -39,7 +39,7 @@ type QualifResults<'mir, 'tcx, Q> = #[derive(Default)] pub struct Qualifs<'mir, 'tcx> { has_mut_interior: Option<QualifResults<'mir, 'tcx, HasMutInterior>>, - needs_drop: Option<QualifResults<'mir, 'tcx, NeedsDrop>>, + needs_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>, indirectly_mutable: Option<IndirectlyMutableResults<'mir, 'tcx>>, } @@ -80,14 +80,14 @@ impl Qualifs<'mir, 'tcx> { location: Location, ) -> bool { let ty = ccx.body.local_decls[local].ty; - if !NeedsDrop::in_any_value_of_ty(ccx, ty) { + if !NeedsNonConstDrop::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) + FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx) .into_engine(tcx, &body) .iterate_to_fixpoint() .into_results_cursor(&body) @@ -988,12 +988,12 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> { let mut err_span = self.span; - // Check to see if the type of this place can ever have a drop impl. If not, this - // `Drop` terminator is frivolous. - let ty_needs_drop = - dropped_place.ty(self.body, self.tcx).ty.needs_drop(self.tcx, self.param_env); + let ty_needs_non_const_drop = qualifs::NeedsNonConstDrop::in_any_value_of_ty( + self.ccx, + dropped_place.ty(self.body, self.tcx).ty, + ); - if !ty_needs_drop { + if !ty_needs_non_const_drop { return; } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs index b08ce219034..f2ba5a1ebb1 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs @@ -5,7 +5,7 @@ use rustc_span::Span; use super::check::Qualifs; use super::ops::{self, NonConstOp}; -use super::qualifs::{NeedsDrop, Qualif}; +use super::qualifs::{NeedsNonConstDrop, Qualif}; use super::ConstCx; /// Returns `true` if we should use the more precise live drop checker that runs after drop @@ -78,10 +78,10 @@ impl Visitor<'tcx> for CheckLiveDrops<'mir, 'tcx> { match &terminator.kind { mir::TerminatorKind::Drop { place: dropped_place, .. } => { let dropped_ty = dropped_place.ty(self.body, self.tcx).ty; - if !NeedsDrop::in_any_value_of_ty(self.ccx, dropped_ty) { - bug!( - "Drop elaboration left behind a Drop for a type that does not need dropping" - ); + if !NeedsNonConstDrop::in_any_value_of_ty(self.ccx, dropped_ty) { + // Instead of throwing a bug, we just return here. This is because we have to + // run custom `const Drop` impls. + return; } if dropped_place.is_indirect() { 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 413a9638eb3..dc3927ed85b 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -3,10 +3,14 @@ //! See the `Qualif` trait for more info. use rustc_errors::ErrorReported; +use rustc_hir as hir; +use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::*; use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty}; use rustc_span::DUMMY_SP; -use rustc_trait_selection::traits; +use rustc_trait_selection::traits::{ + self, ImplSource, Obligation, ObligationCause, SelectionContext, +}; use super::ConstCx; @@ -17,7 +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_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty), custom_eq: CustomEq::in_any_value_of_ty(cx, ty), error_occured, } @@ -97,10 +101,10 @@ impl Qualif for HasMutInterior { /// 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. -pub struct NeedsDrop; +pub struct NeedsNonConstDrop; -impl Qualif for NeedsDrop { - const ANALYSIS_NAME: &'static str = "flow_needs_drop"; +impl Qualif for NeedsNonConstDrop { + const ANALYSIS_NAME: &'static str = "flow_needs_nonconst_drop"; const IS_CLEARED_ON_MOVE: bool = true; fn in_qualifs(qualifs: &ConstQualifs) -> bool { @@ -108,11 +112,37 @@ impl Qualif for NeedsDrop { } fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.needs_drop(cx.tcx, cx.param_env) + let drop_trait = if let Some(did) = cx.tcx.lang_items().drop_trait() { + did + } else { + // there is no way to define a type that needs non-const drop + // without having the lang item present. + return false; + }; + let trait_ref = + ty::TraitRef { def_id: drop_trait, substs: cx.tcx.mk_substs_trait(ty, &[]) }; + let obligation = Obligation::new( + ObligationCause::dummy(), + cx.param_env, + ty::Binder::dummy(ty::TraitPredicate { + trait_ref, + constness: ty::BoundConstness::ConstIfConst, + }), + ); + + let implsrc = cx.tcx.infer_ctxt().enter(|infcx| { + let mut selcx = SelectionContext::with_constness(&infcx, hir::Constness::Const); + selcx.select(&obligation) + }); + match implsrc { + Ok(Some(ImplSource::ConstDrop(_))) + | Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => false, + _ => true, + } } fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool { - adt.has_dtor(cx.tcx) + adt.has_non_const_dtor(cx.tcx) } } diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 8c24c9fa976..52d04cb4ff1 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -231,7 +231,7 @@ impl<'tcx> Validator<'_, 'tcx> { // We cannot promote things that need dropping, since the promoted value // would not get dropped. - if self.qualif_local::<qualifs::NeedsDrop>(place.local) { + if self.qualif_local::<qualifs::NeedsNonConstDrop>(place.local) { return Err(Unpromotable); } |
