Skip to content

Commit

Permalink
Rollup merge of rust-lang#122468 - beepster4096:borrowck_prefixes_cle…
Browse files Browse the repository at this point in the history
…anup, r=Nadrieril

Cleanup `MirBorrowckCtxt::prefixes`

Some of the uses of this method aren't necessary anymore and `PrefixSet::Supporting` is not used anywhere.

With `PrefixSet::Supporting` removed, this could technically be moved to an extension trait on `PlaceRef`. However, it would have to be moved back to `MirBorrowckCtxt` when the `Derefer` MIR pass is moved before borrowck so I didn't.
  • Loading branch information
GuillaumeGomez authored Mar 15, 2024
2 parents 47be8e8 + a5cb61d commit 5c0012b
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 88 deletions.
27 changes: 7 additions & 20 deletions compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead;
use crate::diagnostics::{find_all_local_uses, CapturedMessageOpt};
use crate::{
borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
InitializationRequiringAction, MirBorrowckCtxt, WriteKind,
};

use super::{
Expand Down Expand Up @@ -114,7 +114,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.buffer_error(err);
} else {
if let Some((reported_place, _)) = self.has_move_error(&move_out_indices) {
if self.prefixes(*reported_place, PrefixSet::All).any(|p| p == used_place) {
if used_place.is_prefix_of(*reported_place) {
debug!(
"report_use_of_moved_or_uninitialized place: error suppressed mois={:?}",
move_out_indices
Expand Down Expand Up @@ -1995,34 +1995,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
kind: Option<WriteKind>,
) {
let drop_span = place_span.1;
let root_place =
self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
let borrowed_local = borrow.borrowed_place.local;

let borrow_spans = self.retrieve_borrow_spans(borrow);
let borrow_span = borrow_spans.var_or_use_path_span();

assert!(root_place.projection.is_empty());
let proper_span = self.body.local_decls[root_place.local].source_info.span;

let root_place_projection = self.infcx.tcx.mk_place_elems(root_place.projection);
let proper_span = self.body.local_decls[borrowed_local].source_info.span;

if self.access_place_error_reported.contains(&(
Place { local: root_place.local, projection: root_place_projection },
borrow_span,
)) {
if self.access_place_error_reported.contains(&(Place::from(borrowed_local), borrow_span)) {
debug!(
"suppressing access_place error when borrow doesn't live long enough for {:?}",
borrow_span
);
return;
}

self.access_place_error_reported.insert((
Place { local: root_place.local, projection: root_place_projection },
borrow_span,
));
self.access_place_error_reported.insert((Place::from(borrowed_local), borrow_span));

let borrowed_local = borrow.borrowed_place.local;
if self.body.local_decls[borrowed_local].is_ref_to_thread_local() {
let err =
self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span);
Expand Down Expand Up @@ -2544,9 +2533,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
};
(format!("{local_kind}`{place_desc}`"), format!("`{place_desc}` is borrowed here"))
} else {
let root_place =
self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
let local = root_place.local;
let local = borrow.borrowed_place.local;
match self.body.local_kind(local) {
LocalKind::Arg => (
"function parameter".to_string(),
Expand Down
89 changes: 21 additions & 68 deletions compiler/rustc_borrowck/src/prefixes.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
//! From the NLL RFC: "The deep [aka 'supporting'] prefixes for an
//! place are formed by stripping away fields and derefs, except that
//! we stop when we reach the deref of a shared reference. [...] "
//!
//! From the NLL RFC:
//! "Shallow prefixes are found by stripping away fields, but stop at
//! any dereference. So: writing a path like `a` is illegal if `a.b`
//! is borrowed. But: writing `a` is legal if `*a` is borrowed,
//! whether or not `a` is a shared or mutable reference. [...] "

use super::MirBorrowckCtxt;

use rustc_hir as hir;
use rustc_middle::mir::{Body, PlaceRef, ProjectionElem};
use rustc_middle::ty::{self, TyCtxt};
use rustc_middle::mir::{PlaceRef, ProjectionElem};

pub trait IsPrefixOf<'tcx> {
fn is_prefix_of(&self, other: PlaceRef<'tcx>) -> bool;
Expand All @@ -25,9 +20,7 @@ impl<'tcx> IsPrefixOf<'tcx> for PlaceRef<'tcx> {
}
}

pub(super) struct Prefixes<'cx, 'tcx> {
body: &'cx Body<'tcx>,
tcx: TyCtxt<'tcx>,
pub(super) struct Prefixes<'tcx> {
kind: PrefixSet,
next: Option<PlaceRef<'tcx>>,
}
Expand All @@ -39,24 +32,18 @@ pub(super) enum PrefixSet {
All,
/// Stops at any dereference.
Shallow,
/// Stops at the deref of a shared reference.
Supporting,
}

impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// Returns an iterator over the prefixes of `place`
/// (inclusive) from longest to smallest, potentially
/// terminating the iteration early based on `kind`.
pub(super) fn prefixes(
&self,
place_ref: PlaceRef<'tcx>,
kind: PrefixSet,
) -> Prefixes<'cx, 'tcx> {
Prefixes { next: Some(place_ref), kind, body: self.body, tcx: self.infcx.tcx }
pub(super) fn prefixes(&self, place_ref: PlaceRef<'tcx>, kind: PrefixSet) -> Prefixes<'tcx> {
Prefixes { next: Some(place_ref), kind }
}
}

impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
impl<'tcx> Iterator for Prefixes<'tcx> {
type Item = PlaceRef<'tcx>;
fn next(&mut self) -> Option<Self::Item> {
let mut cursor = self.next?;
Expand Down Expand Up @@ -91,57 +78,23 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
panic!("Subtype projection is not allowed before borrow check")
}
ProjectionElem::Deref => {
// (handled below)
match self.kind {
PrefixSet::Shallow => {
// Shallow prefixes are found by stripping away
// fields, but stop at *any* dereference.
// So we can just stop the traversal now.
self.next = None;
return Some(cursor);
}
PrefixSet::All => {
// All prefixes: just blindly enqueue the base
// of the projection.
self.next = Some(cursor_base);
return Some(cursor);
}
}
}
}

assert_eq!(elem, ProjectionElem::Deref);

match self.kind {
PrefixSet::Shallow => {
// Shallow prefixes are found by stripping away
// fields, but stop at *any* dereference.
// So we can just stop the traversal now.
self.next = None;
return Some(cursor);
}
PrefixSet::All => {
// All prefixes: just blindly enqueue the base
// of the projection.
self.next = Some(cursor_base);
return Some(cursor);
}
PrefixSet::Supporting => {
// Fall through!
}
}

assert_eq!(self.kind, PrefixSet::Supporting);
// Supporting prefixes: strip away fields and
// derefs, except we stop at the deref of a shared
// reference.

let ty = cursor_base.ty(self.body, self.tcx).ty;
match ty.kind() {
ty::RawPtr(_) | ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Not) => {
// don't continue traversing over derefs of raw pointers or shared
// borrows.
self.next = None;
return Some(cursor);
}

ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Mut) => {
self.next = Some(cursor_base);
return Some(cursor);
}

ty::Adt(..) if ty.is_box() => {
self.next = Some(cursor_base);
return Some(cursor);
}

_ => panic!("unknown type fed to Projection Deref."),
}
}
}
}
Expand Down

0 comments on commit 5c0012b

Please sign in to comment.