diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 5bfe5ee64f050..dd6c98f806c4e 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -12,7 +12,9 @@ use rustc_mir_dataflow::impls::{ use rustc_mir_dataflow::{Analysis, GenKill, JoinSemiLattice}; use tracing::debug; -use crate::{BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, places_conflict}; +use crate::{ + AccessDepth, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, places_conflict, +}; // This analysis is different to most others. Its results aren't computed with // `iterate_to_fixpoint`, but are instead composed from the results of three sub-analyses that are @@ -474,7 +476,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { // If the borrowed place is a local with no projections, all other borrows of this // local must conflict. This is purely an optimization so we don't have to call - // `places_conflict` for every borrow. + // `places_conflict::borrow_conflicts_with_place` for every borrow. if place.projection.is_empty() { if !self.body.local_decls[place.local].is_ref_to_static() { state.kill_all(other_borrows_of_local); @@ -487,11 +489,13 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { // will be assured that two places being compared definitely denotes the same sets of // locations. let definitely_conflicting_borrows = other_borrows_of_local.filter(|&i| { - places_conflict( + places_conflict::borrow_conflicts_with_place( self.tcx, self.body, self.borrow_set[i].borrowed_place, - place, + self.borrow_set[i].kind, + place.as_ref(), + AccessDepth::Deep, PlaceConflictBias::NoOverlap, ) }); diff --git a/tests/ui/borrowck/dont-kill-shallow-borrows-on-child-writes.rs b/tests/ui/borrowck/dont-kill-shallow-borrows-on-child-writes.rs new file mode 100644 index 0000000000000..2828647348712 --- /dev/null +++ b/tests/ui/borrowck/dont-kill-shallow-borrows-on-child-writes.rs @@ -0,0 +1,32 @@ +//! Regression test for . On assignment statements, +//! borrowck's dataflow analysis kills borrows that it knows conflict with the assigment: a borrow +//! of a place can't be live anymore after that place is assigned over. Previously, this didn't +//! account for fake borrows being shallow: it would kill any shallow borrows that would have +//! conflicted if they were normal borrows. This made it possible to circumvent fake borrows for +//! match guards and indexing expressions. + +fn test_match_guard() { + let mut a = (Some(&42u64), 0u8); + let mut b = (None::<&u64>, 0u8); + let mut p = &mut a; + // Writing to `(*p).1` in the match guard previously killed the fake borrow of `p` in the guard, + // making it possible to mutate `p` despite `(*p).0` being matched on. This would reach the + // `Some(r)` branch with `(*p).0` being `None`, so the `r` binding was invalid. + match p.0 { + Some(_) if { p.1 = 1; p = &mut b; false } => unreachable!(), + //~^ ERROR: cannot assign `p` in match guard + Some(r) => println!("{r}"), + None => unreachable!(), + } +} + +fn test_indexing() { + let mut x: &mut [&mut [u32]] = &mut [&mut [0]]; + let y: &mut [&mut [u32]] = &mut []; + // Writing to `x[0][0]` previously killed the fake borrow of `x` in the index expression, making + // it possible to access `y[0]` without a bounds-check. + x[0][{ x[0][0] = 1; x = y; 0 }]; + //~^ ERROR: cannot assign `x` in indexing expression +} + +fn main() {} diff --git a/tests/ui/borrowck/dont-kill-shallow-borrows-on-child-writes.stderr b/tests/ui/borrowck/dont-kill-shallow-borrows-on-child-writes.stderr new file mode 100644 index 0000000000000..b45a75a9c6340 --- /dev/null +++ b/tests/ui/borrowck/dont-kill-shallow-borrows-on-child-writes.stderr @@ -0,0 +1,19 @@ +error[E0510]: cannot assign `p` in match guard + --> $DIR/dont-kill-shallow-borrows-on-child-writes.rs:16:31 + | +LL | match p.0 { + | --- value is immutable in match guard +LL | Some(_) if { p.1 = 1; p = &mut b; false } => unreachable!(), + | ^^^^^^^^^^ cannot assign + +error[E0510]: cannot assign `x` in indexing expression + --> $DIR/dont-kill-shallow-borrows-on-child-writes.rs:28:25 + | +LL | x[0][{ x[0][0] = 1; x = y; 0 }]; + | ---- ^^^^^ cannot assign + | | + | value is immutable in indexing expression + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0510`.