Skip to content
Open
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
4 changes: 2 additions & 2 deletions compiler/rustc_borrowck/src/diagnostics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
// we'll use this to check whether it was originally from an overloaded
// operator.
match self.move_data.rev_lookup.find(deref_base) {
LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => {
LookupResult::Exact(mpi) | LookupResult::Parent { mpi, .. } => {
debug!("borrowed_content_source: mpi={:?}", mpi);

for i in &self.move_data.init_path_map[mpi] {
Expand Down Expand Up @@ -594,7 +594,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
}
}
// Base is a `static` so won't be from an overloaded operator
_ => (),
LookupResult::None => (),
};

// If we didn't find an overloaded deref or index, then assume it's a
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_borrowck/src/diagnostics/move_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> {

match self.move_data.rev_lookup.find(match_place.as_ref()) {
// Error with the match place
LookupResult::Parent(_) => {
LookupResult::Parent { .. } | LookupResult::None => {
for ge in &mut *grouped_errors {
if let GroupedMoveError::MovesFromPlace { span, binds_to, .. } = ge
&& match_span == *span
Expand Down Expand Up @@ -219,7 +219,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> {
}
// Error with the pattern
LookupResult::Exact(_) => {
let LookupResult::Parent(Some(mpi)) =
let LookupResult::Parent { mpi, .. } =
self.move_data.rev_lookup.find(move_from.as_ref())
else {
// move_from should be a projection from match_place.
Expand Down
56 changes: 32 additions & 24 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2072,15 +2072,42 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
// This code covers scenarios 1, 2, and 3.

debug!("check_if_full_path_is_moved place: {:?}", place_span.0);
let (prefix, mpi) = self.move_path_closest_to(place_span.0);
if maybe_uninits.contains(mpi) {

let uninit_mpi = match self.move_data.rev_lookup.find(place_span.0) {
// Index projections arbitrarily overlap sibling move paths, so we need to check all descendents of the parent
// Subslice and ConstantIndex projections of slices also overlap siblings,
// but the parent slice will never have a move path
// Subslice projections of arrays are specifically checked in `check_if_subslice_element_is_moved`
LookupResult::Parent { mpi, next_elem: ProjectionKind::Index(..) } => self
.move_data
.find_in_move_path_or_its_descendants(mpi, |mpi| maybe_uninits.contains(mpi)),

LookupResult::Exact(mpi)
| LookupResult::Parent {
mpi,
next_elem:
ProjectionKind::Deref
| ProjectionKind::Field(..)
| ProjectionKind::ConstantIndex { .. }
| ProjectionKind::Subslice { .. }
| ProjectionKind::Downcast(..)
| ProjectionKind::OpaqueCast(..)
| ProjectionKind::UnwrapUnsafeBinder(..),
} => maybe_uninits.contains(mpi).then_some(mpi),

LookupResult::None => bug!("should have move path for every Local"),
};

if let Some(mpi) = uninit_mpi {
self.report_use_of_moved_or_uninitialized(
location,
desired_action,
(prefix, place_span.0, place_span.1),
(self.move_data.move_paths[mpi].place.as_ref(), place_span.0, place_span.1),
mpi,
);
} // Only query longest prefix with a MovePath, not further
}

// Only query longest prefix with a MovePath, not further
// ancestors; dataflow recurs on children when parents
// move (to support partial (re)inits).
//
Expand Down Expand Up @@ -2202,32 +2229,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
}
}

/// Currently MoveData does not store entries for all places in
/// the input MIR. For example it will currently filter out
/// places that are Copy; thus we do not track places of shared
/// reference type. This routine will walk up a place along its
/// prefixes, searching for a foundational place that *is*
/// tracked in the MoveData.
///
/// An Err result includes a tag indicated why the search failed.
/// Currently this can only occur if the place is built off of a
/// static variable, as we do not track those in the MoveData.
fn move_path_closest_to(&mut self, place: PlaceRef<'tcx>) -> (PlaceRef<'tcx>, MovePathIndex) {
match self.move_data.rev_lookup.find(place) {
LookupResult::Parent(Some(mpi)) | LookupResult::Exact(mpi) => {
(self.move_data.move_paths[mpi].place.as_ref(), mpi)
}
LookupResult::Parent(None) => panic!("should have move path for every Local"),
}
}

fn move_path_for_place(&mut self, place: PlaceRef<'tcx>) -> Option<MovePathIndex> {
// If returns None, then there is no move path corresponding
// to a direct owner of `place` (which means there is nothing
// that borrowck tracks for its analysis).

match self.move_data.rev_lookup.find(place) {
LookupResult::Parent(_) => None,
LookupResult::Parent { .. } | LookupResult::None => None,
LookupResult::Exact(mpi) => Some(mpi),
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/polonius/legacy/accesses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl<'a, 'tcx> Visitor<'tcx> for AccessFactsExtractor<'a, 'tcx> {
match context {
PlaceContext::NonMutatingUse(_)
| PlaceContext::MutatingUse(MutatingUseContext::Borrow) => {
let (LookupResult::Exact(path) | LookupResult::Parent(Some(path))) =
let (LookupResult::Exact(path) | LookupResult::Parent { mpi: path, .. }) =
self.move_data.rev_lookup.find(place.as_ref())
else {
// There's no path access to emit.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ pub fn on_lookup_result_bits<'tcx, F>(
F: FnMut(MovePathIndex),
{
match lookup_result {
LookupResult::Parent(..) => {
LookupResult::Parent { .. } | LookupResult::None => {
// access to untracked value - do not touch children
}
LookupResult::Exact(e) => on_all_children_bits(move_data, e, each_child),
Expand Down
21 changes: 14 additions & 7 deletions compiler/rustc_mir_dataflow/src/move_paths/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,11 +344,18 @@ pub enum LookupResult {
/// This exact thing has a move path. E.g. we looked up `x` or `x.m` and it has been moved.
Exact(MovePathIndex),

/// - If the field is `None`, neither the exact thing nor any ancestor of it has a move path.
/// E.g. we looked up `x.m` and neither it nor `x` have a move path.
/// - If the field is `Some`, the exact thing has no move path, but an ancestor does. E.g. we
/// looked up `x.m` which has no move path but `x` has one. Not possible for locals.
Parent(Option<MovePathIndex>),
/// The exact thing has no move path, but an ancestor does.
/// E.g. we looked up `x.m` which has no move path but `x` has one. Not possible for locals.
Parent {
mpi: MovePathIndex,

/// The projection in the place immediately projecting from the parent move path.
next_elem: ProjectionKind,
},

/// Neither the exact thing nor any ancestor of it has a move path.
/// E.g. we looked up `x.m` and neither it nor `x` have a move path.
None,
}

impl<'tcx> MovePathLookup<'tcx> {
Expand All @@ -359,7 +366,7 @@ impl<'tcx> MovePathLookup<'tcx> {
pub fn find(&self, place: PlaceRef<'tcx>) -> LookupResult {
// Look first in the locals (roots).
let Some(mut result) = self.find_local(place.local) else {
return LookupResult::Parent(None);
return LookupResult::None;
};

// Look for a projection through the found local.
Expand All @@ -372,7 +379,7 @@ impl<'tcx> MovePathLookup<'tcx> {
};

let Some(&subpath) = subpath else {
return LookupResult::Parent(Some(result));
return LookupResult::Parent { mpi: result, next_elem: elem.kind() };
};
result = subpath;
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_dataflow/src/rustc_peek.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ where
}
}

LookupResult::Parent(..) => {
LookupResult::Parent { .. } | LookupResult::None => {
tcx.dcx().emit_err(PeekArgumentUntracked { span: call.span });
}
}
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_mir_transform/src/elaborate_drops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,8 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> {
}
});
}
LookupResult::Parent(None) => {}
LookupResult::Parent(Some(parent)) => {
LookupResult::None => {}
LookupResult::Parent { mpi: parent, .. } => {
if self.body.local_decls[place.local].is_deref_temp() {
continue;
}
Expand Down Expand Up @@ -387,8 +387,8 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> {
drop,
)
}
LookupResult::Parent(None) => {}
LookupResult::Parent(Some(_)) => {
LookupResult::None => {}
LookupResult::Parent { .. } => {
if !replace {
self.tcx.dcx().span_bug(
terminator.source_info.span,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ impl<'a, 'mir, 'tcx> DropsReachable<'a, 'mir, 'tcx> {
}
MovePathIndexAtBlock::Unknown => {
if let TerminatorKind::Drop { place, .. } = &terminator.kind
&& let LookupResult::Exact(idx) | LookupResult::Parent(Some(idx)) =
&& let LookupResult::Exact(idx) | LookupResult::Parent { mpi: idx, .. } =
self.move_data.rev_lookup.find(place.as_ref())
{
// Since we are working with MIRs at a very early stage, observing a `drop`
Expand Down
8 changes: 8 additions & 0 deletions tests/ui/borrowck/index-after-constantindex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// test that an Index projection fails after a sibling ConstantIndex projection is moved out of
// regression test for #160525

fn main() {
let mut arr = [[Box::new(42)]];
let alias = &mut arr[0][{ let [row] = arr; drop(row); 0 }]; //~ ERROR
println!("{}", **alias); // use-after-free of arr's dead stack slot
}
18 changes: 18 additions & 0 deletions tests/ui/borrowck/index-after-constantindex.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error[E0382]: borrow of moved value: `arr[..]`
--> $DIR/index-after-constantindex.rs:6:17
|
LL | let alias = &mut arr[0][{ let [row] = arr; drop(row); 0 }];
| ^^^^^^^^^^^^^^^^^^^---^^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | value moved here
| value borrowed here after move
|
= note: move occurs because `arr[..]` has type `[Box<i32>; 1]`, which does not implement the `Copy` trait
help: borrow this binding in the pattern to avoid moving the value
|
LL | let alias = &mut arr[0][{ let [ref row] = arr; drop(row); 0 }];
| +++

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0382`.
Loading