diff --git a/src/analyze/basic_block/visitor/reborrow.rs b/src/analyze/basic_block/visitor/reborrow.rs index 32af11d2..aa51bae2 100644 --- a/src/analyze/basic_block/visitor/reborrow.rs +++ b/src/analyze/basic_block/visitor/reborrow.rs @@ -95,6 +95,16 @@ impl<'a, 'tcx, 'ctx> mir::visit::MutVisitor<'tcx> for ReborrowVisitor<'a, 'tcx, self.super_assign(place, rvalue, location); } + fn visit_rvalue(&mut self, rvalue: &mut mir::Rvalue<'tcx>, location: mir::Location) { + // `PtrMetadata` only reads the length out of the reference it is applied to, so its + // operand needs no reborrow. `analyze_assignment` takes the shared borrow it needs. + if let mir::Rvalue::UnaryOp(mir::UnOp::PtrMetadata, _) = rvalue { + return; + } + + self.super_rvalue(rvalue, location); + } + // TODO: is it always true that the operand is not referred again in rvalue fn visit_operand(&mut self, operand: &mut mir::Operand<'tcx>, location: mir::Location) { let Some(p) = operand.place() else { diff --git a/tests/ui/fail/slice_len_guard_mut.rs b/tests/ui/fail/slice_len_guard_mut.rs new file mode 100644 index 00000000..de2c5074 --- /dev/null +++ b/tests/ui/fail/slice_len_guard_mut.rs @@ -0,0 +1,12 @@ +//@error-in-other-file: Unsat +//@compile-flags: -C debug-assertions=off -C opt-level=2 + +#[thrust::callable] +fn check(v: &mut [i32], i: usize) { + if i < v.len() { + v[i] = 7; + assert!(v[i] == 8); + } +} + +fn main() {} diff --git a/tests/ui/pass/slice_len_guard_mut.rs b/tests/ui/pass/slice_len_guard_mut.rs new file mode 100644 index 00000000..23950648 --- /dev/null +++ b/tests/ui/pass/slice_len_guard_mut.rs @@ -0,0 +1,16 @@ +//@check-pass +//@compile-flags: -C debug-assertions=off -C opt-level=2 + +// At `-C opt-level=1` and above rustc reads slice metadata straight off the `&mut [i32]` +// local (`_len = PtrMetadata(copy _v)`) instead of through a shared reborrow, so this pins +// down that the length `len()` returns still describes the referent the guarded index +// reads. +#[thrust::callable] +fn check(v: &mut [i32], i: usize) { + if i < v.len() { + v[i] = 7; + assert!(v[i] == 7); + } +} + +fn main() {}