Ignore mut borrow from drop terminator in const-eval
This commit is contained in:
parent
15a5382ef1
commit
0984639348
@ -22,13 +22,14 @@
|
||||
/// 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,18 +188,13 @@ 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, .. } => {
|
||||
// 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
|
||||
| TerminatorKind::Assert { .. }
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user