]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_const_eval/src/transform/check_consts/check.rs
Rollup merge of #89876 - AlexApps99:const_ops, r=oli-obk
[rust.git] / compiler / rustc_const_eval / src / transform / check_consts / check.rs
index d704c4335c7540503b371e146fb38f31aaf7465a..3a5bc37b85ad6937da526276508e61b31da90e8c 100644 (file)
@@ -12,7 +12,6 @@
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
 use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
 use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
-use rustc_mir_dataflow::impls::MaybeMutBorrowedLocals;
 use rustc_mir_dataflow::{self, Analysis};
 use rustc_span::{sym, Span, Symbol};
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
 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 super::{ConstCx, Qualif};
 use crate::const_eval::is_unstable_const_fn;
 
-// We are using `MaybeMutBorrowedLocals` as a proxy for whether an item may have been mutated
-// through a pointer prior to the given point. This is okay even though `MaybeMutBorrowedLocals`
-// kills locals upon `StorageDead` because a local will never be used after a `StorageDead`.
-type IndirectlyMutableResults<'mir, 'tcx> =
-    rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, MaybeMutBorrowedLocals<'mir, 'tcx>>;
-
 type QualifResults<'mir, 'tcx, Q> =
     rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>;
 
 #[derive(Default)]
 pub struct Qualifs<'mir, 'tcx> {
     has_mut_interior: Option<QualifResults<'mir, 'tcx, HasMutInterior>>,
-    needs_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>,
-    indirectly_mutable: Option<IndirectlyMutableResults<'mir, 'tcx>>,
+    needs_drop: Option<QualifResults<'mir, 'tcx, NeedsDrop>>,
+    needs_non_const_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>,
 }
 
 impl Qualifs<'mir, 'tcx> {
-    pub fn indirectly_mutable(
+    /// 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 indirectly_mutable = self.indirectly_mutable.get_or_insert_with(|| {
-            let ConstCx { tcx, body, param_env, .. } = *ccx;
-
-            // We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not
-            // allowed in a const.
-            //
-            // FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this
-            // without breaking stable code?
-            MaybeMutBorrowedLocals::mut_borrows_only(tcx, &body, param_env)
-                .unsound_ignore_borrow_on_drop()
+        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)
-                .pass_name("const_qualification")
                 .iterate_to_fixpoint()
                 .into_results_cursor(&body)
         });
 
-        indirectly_mutable.seek_before_primary_effect(location);
-        indirectly_mutable.get().contains(local)
+        needs_drop.seek_before_primary_effect(location);
+        needs_drop.get().contains(local)
     }
 
-    /// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
+    /// Returns `true` if `local` is `NeedsNonConstDrop` at the given `Location`.
     ///
     /// Only updates the cursor if absolutely necessary
-    pub fn needs_drop(
+    pub fn needs_non_const_drop(
         &mut self,
         ccx: &'mir ConstCx<'mir, 'tcx>,
         local: Local,
@@ -84,7 +78,7 @@ pub fn needs_drop(
             return false;
         }
 
-        let needs_drop = self.needs_drop.get_or_insert_with(|| {
+        let needs_non_const_drop = self.needs_non_const_drop.get_or_insert_with(|| {
             let ConstCx { tcx, body, .. } = *ccx;
 
             FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx)
@@ -93,8 +87,8 @@ pub fn needs_drop(
                 .into_results_cursor(&body)
         });
 
-        needs_drop.seek_before_primary_effect(location);
-        needs_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location)
+        needs_non_const_drop.seek_before_primary_effect(location);
+        needs_non_const_drop.get().contains(local)
     }
 
     /// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
@@ -121,7 +115,7 @@ pub fn has_mut_interior(
         });
 
         has_mut_interior.seek_before_primary_effect(location);
-        has_mut_interior.get().contains(local) || self.indirectly_mutable(ccx, local, location)
+        has_mut_interior.get().contains(local)
     }
 
     fn in_return_place(
@@ -167,12 +161,13 @@ fn in_return_place(
                     .into_results_cursor(&ccx.body);
 
                 cursor.seek_after_primary_effect(return_loc);
-                cursor.contains(RETURN_PLACE)
+                cursor.get().contains(RETURN_PLACE)
             }
         };
 
         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,
             error_occured,
@@ -825,6 +820,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                         Binder::dummy(TraitPredicate {
                             trait_ref,
                             constness: ty::BoundConstness::ConstIfConst,
+                            polarity: ty::ImplPolarity::Positive,
                         }),
                     );
 
@@ -888,31 +884,27 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 }
 
                 // At this point, we are calling a function, `callee`, whose `DefId` is known...
-                if is_lang_special_const_fn(tcx, callee) {
-                    // `begin_panic` and `panic_display` are generic functions that accept
-                    // types other than str. Check to enforce that only str can be used in
-                    // const-eval.
-
-                    // const-eval of the `begin_panic` fn assumes the argument is `&str`
-                    if Some(callee) == tcx.lang_items().begin_panic_fn() {
-                        match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
-                            ty::Ref(_, ty, _) if ty.is_str() => (),
-                            _ => self.check_op(ops::PanicNonStr),
-                        }
-                    }
 
-                    // const-eval of the `panic_display` fn assumes the argument is `&&str`
-                    if Some(callee) == tcx.lang_items().panic_display() {
-                        match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
-                            ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) =>
-                                {}
-                            _ => self.check_op(ops::PanicNonStr),
-                        }
+                // `begin_panic` and `panic_display` are generic functions that accept
+                // types other than str. Check to enforce that only str can be used in
+                // const-eval.
+
+                // const-eval of the `begin_panic` fn assumes the argument is `&str`
+                if Some(callee) == tcx.lang_items().begin_panic_fn() {
+                    match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
+                        ty::Ref(_, ty, _) if ty.is_str() => return,
+                        _ => self.check_op(ops::PanicNonStr),
                     }
+                }
 
-                    if is_lang_panic_fn(tcx, callee) {
-                        // run stability check on non-panic special const fns.
-                        return;
+                // const-eval of the `panic_display` fn assumes the argument is `&&str`
+                if Some(callee) == tcx.lang_items().panic_display() {
+                    match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
+                        ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) =>
+                        {
+                            return;
+                        }
+                        _ => self.check_op(ops::PanicNonStr),
                     }
                 }
 
@@ -999,7 +991,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
             }
 
             // Forbid all `Drop` terminators unless the place being dropped is a local with no
-            // projections that cannot be `NeedsDrop`.
+            // projections that cannot be `NeedsNonConstDrop`.
             TerminatorKind::Drop { place: dropped_place, .. }
             | TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
                 // If we are checking live drops after drop-elaboration, don't emit duplicate
@@ -1019,15 +1011,15 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                     return;
                 }
 
-                let needs_drop = if let Some(local) = dropped_place.as_local() {
+                let needs_non_const_drop = if let Some(local) = dropped_place.as_local() {
                     // Use the span where the local was declared as the span of the drop error.
                     err_span = self.body.local_decls[local].source_info.span;
-                    self.qualifs.needs_drop(self.ccx, local, location)
+                    self.qualifs.needs_non_const_drop(self.ccx, local, location)
                 } else {
                     true
                 };
 
-                if needs_drop {
+                if needs_non_const_drop {
                     self.check_op_spanned(
                         ops::LiveDrop { dropped_at: Some(terminator.source_info.span) },
                         err_span,