Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup MirBorrowckCtxt::prefixes #122468

Merged
merged 1 commit into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading