diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index bf7589e84ad..487e229543a 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1401,8 +1401,13 @@ impl<'hir> LoweringContext<'_, 'hir> { ) }; + // #82462: to correctly diagnose borrow errors, the block that contains + // the iter expr needs to have a span that covers the loop body. + let desugared_full_span = + self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), e.span, None); + let match_expr = self.arena.alloc(self.expr_match( - desugared_span, + desugared_full_span, into_iter_expr, arena_vec![self; iter_arm], hir::MatchSource::ForLoopDesugar, @@ -1416,7 +1421,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // surrounding scope of the `match` since the `match` is not a terminating scope. // // Also, add the attributes to the outer returned expr node. - self.expr_drop_temps_mut(desugared_span, match_expr, attrs.into()) + self.expr_drop_temps_mut(desugared_full_span, match_expr, attrs.into()) } /// Desugar `ExprKind::Try` from: `?` into: diff --git a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff index 80024124dc5..1a4e30bbfff 100644 --- a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff +++ b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff @@ -80,7 +80,7 @@ - StorageDead(_7); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19 - StorageDead(_6); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6 - StorageDead(_4); // scope 1 at $DIR/remove_storage_markers.rs:10:5: 10:6 -- StorageDead(_2); // scope 1 at $DIR/remove_storage_markers.rs:8:18: 8:19 +- StorageDead(_2); // scope 1 at $DIR/remove_storage_markers.rs:10:5: 10:6 - StorageDead(_1); // scope 0 at $DIR/remove_storage_markers.rs:11:1: 11:2 return; // scope 0 at $DIR/remove_storage_markers.rs:11:2: 11:2 } diff --git a/src/test/ui/borrowck/issue-82462.nll.stderr b/src/test/ui/borrowck/issue-82462.nll.stderr new file mode 100644 index 00000000000..10497c30e64 --- /dev/null +++ b/src/test/ui/borrowck/issue-82462.nll.stderr @@ -0,0 +1,22 @@ +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/issue-82462.rs:18:9 + | +LL | for x in DroppingSlice(&*v).iter() { + | ------------------ + | | | + | | immutable borrow occurs here + | a temporary with access to the immutable borrow is created here ... +LL | v.push(*x); + | ^ mutable borrow occurs here +LL | break; +LL | } + | - ... and the immutable borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DroppingSlice` + | +help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped + | +LL | }; + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/issue-82462.rs b/src/test/ui/borrowck/issue-82462.rs new file mode 100644 index 00000000000..5a3c64255cc --- /dev/null +++ b/src/test/ui/borrowck/issue-82462.rs @@ -0,0 +1,21 @@ +struct DroppingSlice<'a>(&'a [i32]); + +impl Drop for DroppingSlice<'_> { + fn drop(&mut self) { + println!("hi from slice"); + } +} + +impl DroppingSlice<'_> { + fn iter(&self) -> std::slice::Iter<'_, i32> { + self.0.iter() + } +} + +fn main() { + let mut v = vec![1, 2, 3, 4]; + for x in DroppingSlice(&*v).iter() { + v.push(*x); //~ERROR + break; + } +} diff --git a/src/test/ui/borrowck/issue-82462.stderr b/src/test/ui/borrowck/issue-82462.stderr new file mode 100644 index 00000000000..a2c291f7797 --- /dev/null +++ b/src/test/ui/borrowck/issue-82462.stderr @@ -0,0 +1,22 @@ +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/issue-82462.rs:18:9 + | +LL | for x in DroppingSlice(&*v).iter() { + | ------------------ + | | | + | | immutable borrow occurs here + | a temporary with access to the immutable borrow is created here ... +LL | v.push(*x); + | ^^^^^^^^^^ mutable borrow occurs here +LL | break; +LL | } + | - ... and the immutable borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DroppingSlice` + | +help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped + | +LL | }; + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`.