use crate::{AnalysisDomain, GenKill, GenKillAnalysis};
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
-use rustc_middle::ty::{ParamEnv, TyCtxt};
-use rustc_span::DUMMY_SP;
-
-pub type MaybeMutBorrowedLocals<'mir, 'tcx> = MaybeBorrowedLocals<MutBorrow<'mir, 'tcx>>;
/// A dataflow analysis that tracks whether a pointer or reference could possibly exist that points
/// to a given local.
///
-/// The `K` parameter determines what kind of borrows are tracked. By default,
-/// `MaybeBorrowedLocals` looks for *any* borrow of a local. If you are only interested in borrows
-/// that might allow mutation, use the `MaybeMutBorrowedLocals` type alias instead.
-///
/// At present, this is used as a very limited form of alias analysis. For example,
/// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for
-/// immovable generators. `MaybeMutBorrowedLocals` is used during const checking to prove that a
-/// local has not been mutated via indirect assignment (e.g., `*p = 42`), the side-effects of a
-/// function call or inline assembly.
-pub struct MaybeBorrowedLocals<K = AnyBorrow> {
- kind: K,
+/// immovable generators.
+pub struct MaybeBorrowedLocals {
ignore_borrow_on_drop: bool,
}
/// 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, ignore_borrow_on_drop: false }
- }
-}
-
-impl MaybeMutBorrowedLocals<'mir, 'tcx> {
- /// A dataflow analysis that records whether a pointer or reference exists that may *mutably*
- /// alias the given local.
- ///
- /// This includes `&mut` and pointers derived from an `&mut`, as well as shared borrows of
- /// types with interior mutability.
- pub fn mut_borrows_only(
- tcx: TyCtxt<'tcx>,
- body: &'mir mir::Body<'tcx>,
- param_env: ParamEnv<'tcx>,
- ) -> Self {
- MaybeBorrowedLocals {
- kind: MutBorrow { body, tcx, param_env },
- ignore_borrow_on_drop: false,
- }
+ MaybeBorrowedLocals { ignore_borrow_on_drop: false }
}
}
-impl<K> MaybeBorrowedLocals<K> {
+impl MaybeBorrowedLocals {
/// 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
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,
- ignore_borrow_on_drop: self.ignore_borrow_on_drop,
- }
+ fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T> {
+ TransferFunction { trans, ignore_borrow_on_drop: self.ignore_borrow_on_drop }
}
}
-impl<K> AnalysisDomain<'tcx> for MaybeBorrowedLocals<K>
-where
- K: BorrowAnalysisKind<'tcx>,
-{
+impl AnalysisDomain<'tcx> for MaybeBorrowedLocals {
type Domain = BitSet<Local>;
- const NAME: &'static str = K::ANALYSIS_NAME;
+ const NAME: &'static str = "maybe_borrowed_locals";
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
// bottom = unborrowed
}
}
-impl<K> GenKillAnalysis<'tcx> for MaybeBorrowedLocals<K>
-where
- K: BorrowAnalysisKind<'tcx>,
-{
+impl GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
type Idx = Local;
fn statement_effect(
}
/// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`.
-struct TransferFunction<'a, T, K> {
+struct TransferFunction<'a, T> {
trans: &'a mut T,
- kind: &'a K,
ignore_borrow_on_drop: bool,
}
-impl<T, K> Visitor<'tcx> for TransferFunction<'a, T, K>
+impl<T> Visitor<'tcx> for TransferFunction<'a, T>
where
T: GenKill<Local>,
- K: BorrowAnalysisKind<'tcx>,
{
fn visit_statement(&mut self, stmt: &Statement<'tcx>, location: Location) {
self.super_statement(stmt, location);
self.super_rvalue(rvalue, location);
match rvalue {
- mir::Rvalue::AddressOf(mt, borrowed_place) => {
- if !borrowed_place.is_indirect() && self.kind.in_address_of(*mt, *borrowed_place) {
+ mir::Rvalue::AddressOf(_mt, borrowed_place) => {
+ if !borrowed_place.is_indirect() {
self.trans.gen(borrowed_place.local);
}
}
- mir::Rvalue::Ref(_, kind, borrowed_place) => {
- if !borrowed_place.is_indirect() && self.kind.in_ref(*kind, *borrowed_place) {
+ mir::Rvalue::Ref(_, _kind, borrowed_place) => {
+ if !borrowed_place.is_indirect() {
self.trans.gen(borrowed_place.local);
}
}
}
}
}
-
-pub struct AnyBorrow;
-
-pub struct MutBorrow<'mir, 'tcx> {
- tcx: TyCtxt<'tcx>,
- body: &'mir Body<'tcx>,
- param_env: ParamEnv<'tcx>,
-}
-
-impl MutBorrow<'mir, 'tcx> {
- /// `&` and `&raw` only allow mutation if the borrowed place is `!Freeze`.
- ///
- /// This assumes that it is UB to take the address of a struct field whose type is
- /// `Freeze`, then use pointer arithmetic to derive a pointer to a *different* field of
- /// that same struct whose type is `!Freeze`. If we decide that this is not UB, we will
- /// have to check the type of the borrowed **local** instead of the borrowed **place**
- /// below. See [rust-lang/unsafe-code-guidelines#134].
- ///
- /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
- fn shared_borrow_allows_mutation(&self, place: Place<'tcx>) -> bool {
- !place.ty(self.body, self.tcx).ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env)
- }
-}
-
-pub trait BorrowAnalysisKind<'tcx> {
- const ANALYSIS_NAME: &'static str;
-
- fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool;
- fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool;
-}
-
-impl BorrowAnalysisKind<'tcx> for AnyBorrow {
- const ANALYSIS_NAME: &'static str = "maybe_borrowed_locals";
-
- fn in_ref(&self, _: mir::BorrowKind, _: Place<'_>) -> bool {
- true
- }
- fn in_address_of(&self, _: Mutability, _: Place<'_>) -> bool {
- true
- }
-}
-
-impl BorrowAnalysisKind<'tcx> for MutBorrow<'mir, 'tcx> {
- const ANALYSIS_NAME: &'static str = "maybe_mut_borrowed_locals";
-
- fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool {
- match kind {
- mir::BorrowKind::Mut { .. } => true,
- mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => {
- self.shared_borrow_allows_mutation(place)
- }
- }
- }
-
- fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool {
- match mt {
- Mutability::Mut => true,
- Mutability::Not => self.shared_borrow_allows_mutation(place),
- }
- }
-}