about summary refs log tree commit diff
path: root/compiler/rustc_const_eval/src/transform
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-09-15 03:51:03 +0000
committerbors <bors@rust-lang.org>2021-09-15 03:51:03 +0000
commitcdeba02ff71416e014f7130f75166890688be986 (patch)
tree7abdff0663fd163ce1684276436982235b47f082 /compiler/rustc_const_eval/src/transform
parentc3c0f80d6081092faff801542dd82f0e2420152b (diff)
parentf749e05f6b95b66485c0417996d9aeb369def8da (diff)
downloadrust-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')
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs18
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs10
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs44
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs2
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);
                         }