]> git.lizzy.rs Git - rust.git/commitdiff
Ignore mut borrow from drop terminator in const-eval
authorDylan MacKenzie <ecstaticmorse@gmail.com>
Thu, 13 Feb 2020 21:57:01 +0000 (13:57 -0800)
committerDylan MacKenzie <ecstaticmorse@gmail.com>
Thu, 13 Feb 2020 22:15:09 +0000 (14:15 -0800)
src/librustc_mir/dataflow/impls/borrowed_locals.rs
src/librustc_mir/transform/check_consts/validation.rs

index 20aab8b32a51d071c4cb2961f2ad3148d595a4d9..0ce37aea69df3fef60ac4c60154485fd9c7ea858 100644 (file)
 /// function call or inline assembly.
 pub struct MaybeBorrowedLocals<K = AnyBorrow> {
     kind: K,
+    ignore_borrow_on_drop: bool,
 }
 
 impl MaybeBorrowedLocals {
     /// A dataflow analysis that records whether a pointer or reference exists that may alias the
     /// given local.
     pub fn all_borrows() -> Self {
-        MaybeBorrowedLocals { kind: AnyBorrow }
+        MaybeBorrowedLocals { kind: AnyBorrow, ignore_borrow_on_drop: false }
     }
 }
 
@@ -43,13 +44,37 @@ pub fn mut_borrows_only(
         body: &'mir mir::Body<'tcx>,
         param_env: ParamEnv<'tcx>,
     ) -> Self {
-        MaybeBorrowedLocals { kind: MutBorrow { body, tcx, param_env } }
+        MaybeBorrowedLocals {
+            kind: MutBorrow { body, tcx, param_env },
+            ignore_borrow_on_drop: false,
+        }
     }
 }
 
 impl<K> MaybeBorrowedLocals<K> {
+    /// During dataflow analysis, ignore the borrow that may occur when a place is dropped.
+    ///
+    /// Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut self` as a
+    /// parameter. In the general case, a drop impl could launder that reference into the
+    /// surrounding environment through a raw pointer, thus creating a valid `*mut` pointing to the
+    /// dropped local. We are not yet willing to declare this particular case UB, so we must treat
+    /// all dropped locals as mutably borrowed for now. See discussion on [#61069].
+    ///
+    /// In some contexts, we know that this borrow will never occur. For example, during
+    /// const-eval, custom drop glue cannot be run. Code that calls this should document the
+    /// assumptions that justify `Drop` terminators in this way.
+    ///
+    /// [#61069]: https://github.com/rust-lang/rust/pull/61069
+    pub fn unsound_ignore_borrow_on_drop(self) -> Self {
+        MaybeBorrowedLocals { ignore_borrow_on_drop: true, ..self }
+    }
+
     fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T, K> {
-        TransferFunction { kind: &self.kind, trans }
+        TransferFunction {
+            kind: &self.kind,
+            trans,
+            ignore_borrow_on_drop: self.ignore_borrow_on_drop,
+        }
     }
 }
 
@@ -112,6 +137,7 @@ impl<K> BottomValue for MaybeBorrowedLocals<K> {
 struct TransferFunction<'a, T, K> {
     trans: &'a mut T,
     kind: &'a K,
+    ignore_borrow_on_drop: bool,
 }
 
 impl<T, K> Visitor<'tcx> for TransferFunction<'a, T, K>
@@ -162,17 +188,12 @@ fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Loc
         self.super_terminator(terminator, location);
 
         match terminator.kind {
-            // Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut self`
-            // as a parameter. Hypothetically, a drop impl could launder that reference into the
-            // surrounding environment through a raw pointer, thus creating a valid `*mut` pointing
-            // to the dropped local. We are not yet willing to declare this particular case UB, so
-            // we must treat all dropped locals as mutably borrowed for now. See discussion on
-            // [#61069].
-            //
-            // [#61069]: https://github.com/rust-lang/rust/pull/61069
             mir::TerminatorKind::Drop { location: dropped_place, .. }
             | mir::TerminatorKind::DropAndReplace { location: dropped_place, .. } => {
-                self.trans.gen(dropped_place.local);
+                // See documentation for `unsound_ignore_borrow_on_drop` for an explanation.
+                if !self.ignore_borrow_on_drop {
+                    self.trans.gen(dropped_place.local);
+                }
             }
 
             TerminatorKind::Abort
index d9e179ad42a68ee43183125350b900ebf3ed8d83..d4fa2b10152fee2fc5c47602d7c3bd1f1fa120b1 100644 (file)
@@ -141,7 +141,13 @@ pub fn new(item: &'a Item<'mir, 'tcx>) -> Self {
         let needs_drop = QualifCursor::new(NeedsDrop, item);
         let has_mut_interior = QualifCursor::new(HasMutInterior, item);
 
+        // 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?
         let indirectly_mutable = MaybeMutBorrowedLocals::mut_borrows_only(tcx, *body, param_env)
+            .unsound_ignore_borrow_on_drop()
             .into_engine(tcx, *body, def_id)
             .iterate_to_fixpoint()
             .into_results_cursor(*body);