Skip to content

Commit 4e880f8

Browse files
committed
Auto merge of #88214 - notriddle:notriddle/for-loop-span-drop-temps-mut, r=nagisa
rustc: use more correct span data in for loop desugaring Fixes #82462 Before: help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped | LL | for x in DroppingSlice(&*v).iter(); { | + After: help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped | LL | }; | + This seems like a reasonable fix: since the desugared "expr_drop_temps_mut" contains the entire desugared loop construct, its span should contain the entire loop construct as well.
2 parents 22719ef + 543e601 commit 4e880f8

File tree

9 files changed

+82
-13
lines changed

9 files changed

+82
-13
lines changed

Diff for: compiler/rustc_ast_lowering/src/expr.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1450,8 +1450,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
14501450
)
14511451
};
14521452

1453+
// #82462: to correctly diagnose borrow errors, the block that contains
1454+
// the iter expr needs to have a span that covers the loop body.
1455+
let desugared_full_span =
1456+
self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), e.span, None);
1457+
14531458
let match_expr = self.arena.alloc(self.expr_match(
1454-
desugared_span,
1459+
desugared_full_span,
14551460
into_iter_expr,
14561461
arena_vec![self; iter_arm],
14571462
hir::MatchSource::ForLoopDesugar,
@@ -1465,7 +1470,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
14651470
// surrounding scope of the `match` since the `match` is not a terminating scope.
14661471
//
14671472
// Also, add the attributes to the outer returned expr node.
1468-
self.expr_drop_temps_mut(desugared_span, match_expr, attrs.into())
1473+
self.expr_drop_temps_mut(desugared_full_span, match_expr, attrs.into())
14691474
}
14701475

14711476
/// Desugar `ExprKind::Try` from: `<expr>?` into:

Diff for: src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
- StorageDead(_7); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
8181
- StorageDead(_6); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6
8282
- StorageDead(_4); // scope 1 at $DIR/remove_storage_markers.rs:10:5: 10:6
83-
- StorageDead(_2); // scope 1 at $DIR/remove_storage_markers.rs:8:18: 8:19
83+
- StorageDead(_2); // scope 1 at $DIR/remove_storage_markers.rs:10:5: 10:6
8484
- StorageDead(_1); // scope 0 at $DIR/remove_storage_markers.rs:11:1: 11:2
8585
return; // scope 0 at $DIR/remove_storage_markers.rs:11:2: 11:2
8686
}

Diff for: src/test/ui/borrowck/issue-82462.nll.stderr

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
2+
--> $DIR/issue-82462.rs:18:9
3+
|
4+
LL | for x in DroppingSlice(&*v).iter() {
5+
| ------------------
6+
| | |
7+
| | immutable borrow occurs here
8+
| a temporary with access to the immutable borrow is created here ...
9+
LL | v.push(*x);
10+
| ^ mutable borrow occurs here
11+
LL | break;
12+
LL | }
13+
| - ... and the immutable borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DroppingSlice`
14+
|
15+
help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
16+
|
17+
LL | };
18+
| +
19+
20+
error: aborting due to previous error
21+
22+
For more information about this error, try `rustc --explain E0502`.

Diff for: src/test/ui/borrowck/issue-82462.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
struct DroppingSlice<'a>(&'a [i32]);
2+
3+
impl Drop for DroppingSlice<'_> {
4+
fn drop(&mut self) {
5+
println!("hi from slice");
6+
}
7+
}
8+
9+
impl DroppingSlice<'_> {
10+
fn iter(&self) -> std::slice::Iter<'_, i32> {
11+
self.0.iter()
12+
}
13+
}
14+
15+
fn main() {
16+
let mut v = vec![1, 2, 3, 4];
17+
for x in DroppingSlice(&*v).iter() {
18+
v.push(*x); //~ERROR
19+
break;
20+
}
21+
}

Diff for: src/test/ui/borrowck/issue-82462.stderr

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
2+
--> $DIR/issue-82462.rs:18:9
3+
|
4+
LL | for x in DroppingSlice(&*v).iter() {
5+
| ------------------
6+
| | |
7+
| | immutable borrow occurs here
8+
| a temporary with access to the immutable borrow is created here ...
9+
LL | v.push(*x);
10+
| ^^^^^^^^^^ mutable borrow occurs here
11+
LL | break;
12+
LL | }
13+
| - ... and the immutable borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DroppingSlice`
14+
|
15+
help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
16+
|
17+
LL | };
18+
| +
19+
20+
error: aborting due to previous error
21+
22+
For more information about this error, try `rustc --explain E0502`.

Diff for: src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ pub(super) fn check<'tcx>(
1515
pat: &'tcx Pat<'_>,
1616
arg: &'tcx Expr<'_>,
1717
body: &'tcx Expr<'_>,
18-
expr: &'tcx Expr<'_>,
1918
) {
2019
let pat_span = pat.span;
2120

@@ -43,7 +42,7 @@ pub(super) fn check<'tcx>(
4342
span_lint_and_then(
4443
cx,
4544
FOR_KV_MAP,
46-
expr.span,
45+
arg_span,
4746
&format!("you seem to want to iterate on a map's {}s", kind),
4847
|diag| {
4948
let map = sugg::Sugg::hir(cx, arg, "map");

Diff for: src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ use rustc_hir::Expr;
55
use rustc_lint::LateContext;
66
use rustc_span::sym;
77

8-
pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, expr: &Expr<'_>) -> bool {
8+
pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool {
99
if is_trait_method(cx, arg, sym::Iterator) {
1010
span_lint(
1111
cx,
1212
ITER_NEXT_LOOP,
13-
expr.span,
13+
arg.span,
1414
"you are iterating over `Iterator::next()` which is an Option; this will compile but is \
1515
probably not what you want",
1616
);

Diff for: src/tools/clippy/clippy_lints/src/loops/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -616,15 +616,15 @@ fn check_for_loop<'tcx>(
616616
needless_range_loop::check(cx, pat, arg, body, expr);
617617
explicit_counter_loop::check(cx, pat, arg, body, expr);
618618
}
619-
check_for_loop_arg(cx, pat, arg, expr);
620-
for_kv_map::check(cx, pat, arg, body, expr);
619+
check_for_loop_arg(cx, pat, arg);
620+
for_kv_map::check(cx, pat, arg, body);
621621
mut_range_bound::check(cx, arg, body);
622622
single_element_loop::check(cx, pat, arg, body, expr);
623623
same_item_push::check(cx, pat, arg, body, expr);
624624
manual_flatten::check(cx, pat, arg, body, span);
625625
}
626626

627-
fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, expr: &Expr<'_>) {
627+
fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) {
628628
let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used
629629

630630
if let ExprKind::MethodCall(method, _, [self_arg], _) = arg.kind {
@@ -637,7 +637,7 @@ fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, expr:
637637
explicit_into_iter_loop::check(cx, self_arg, arg);
638638
},
639639
"next" => {
640-
next_loop_linted = iter_next_loop::check(cx, arg, expr);
640+
next_loop_linted = iter_next_loop::check(cx, arg);
641641
},
642642
_ => {},
643643
}

Diff for: src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ pub(super) fn check<'tcx>(
144144
span_lint_and_then(
145145
cx,
146146
NEEDLESS_RANGE_LOOP,
147-
expr.span,
147+
arg.span,
148148
&format!("the loop variable `{}` is used to index `{}`", ident.name, indexed),
149149
|diag| {
150150
multispan_sugg(
@@ -170,7 +170,7 @@ pub(super) fn check<'tcx>(
170170
span_lint_and_then(
171171
cx,
172172
NEEDLESS_RANGE_LOOP,
173-
expr.span,
173+
arg.span,
174174
&format!("the loop variable `{}` is only used to index `{}`", ident.name, indexed),
175175
|diag| {
176176
multispan_sugg(

0 commit comments

Comments
 (0)