Skip to content

Commit 01f7352

Browse files
authored
Rollup merge of rust-lang#89895 - camsteffen:for-loop-head-span, r=davidtwco
Don't mark for loop iter expression as desugared We typically don't mark spans of lowered things as desugared. This helps Clippy rightly discern when code is (not) from expansion. This was discovered by `@flip1995` at rust-lang/rust-clippy#7789 (comment).
2 parents 0d70763 + ffdd5a0 commit 01f7352

File tree

6 files changed

+65
-74
lines changed

6 files changed

+65
-74
lines changed

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,15 +1332,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
13321332
body: &Block,
13331333
opt_label: Option<Label>,
13341334
) -> hir::Expr<'hir> {
1335-
let orig_head_span = head.span;
13361335
// expand <head>
1337-
let mut head = self.lower_expr_mut(head);
1338-
let desugared_span = self.mark_span_with_reason(
1339-
DesugaringKind::ForLoop(ForLoopLoc::Head),
1340-
orig_head_span,
1341-
None,
1342-
);
1343-
head.span = self.lower_span(desugared_span);
1336+
let head = self.lower_expr_mut(head);
1337+
let desugared_span =
1338+
self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), head.span, None);
1339+
let e_span = self.lower_span(e.span);
13441340

13451341
let iter = Ident::with_dummy_span(sym::iter);
13461342

@@ -1354,23 +1350,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
13541350
// `::std::option::Option::Some(val) => __next = val`
13551351
let pat_arm = {
13561352
let val_ident = Ident::with_dummy_span(sym::val);
1357-
let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident);
1358-
let val_expr = self.expr_ident(pat.span, val_ident, val_pat_hid);
1359-
let next_expr = self.expr_ident(pat.span, next_ident, next_pat_hid);
1353+
let pat_span = self.lower_span(pat.span);
1354+
let (val_pat, val_pat_hid) = self.pat_ident(pat_span, val_ident);
1355+
let val_expr = self.expr_ident(pat_span, val_ident, val_pat_hid);
1356+
let next_expr = self.expr_ident(pat_span, next_ident, next_pat_hid);
13601357
let assign = self.arena.alloc(self.expr(
1361-
pat.span,
1362-
hir::ExprKind::Assign(next_expr, val_expr, self.lower_span(pat.span)),
1358+
pat_span,
1359+
hir::ExprKind::Assign(next_expr, val_expr, self.lower_span(pat_span)),
13631360
ThinVec::new(),
13641361
));
1365-
let some_pat = self.pat_some(pat.span, val_pat);
1362+
let some_pat = self.pat_some(pat_span, val_pat);
13661363
self.arm(some_pat, assign)
13671364
};
13681365

13691366
// `::std::option::Option::None => break`
13701367
let break_arm = {
13711368
let break_expr =
1372-
self.with_loop_scope(e.id, |this| this.expr_break_alloc(e.span, ThinVec::new()));
1373-
let pat = self.pat_none(e.span);
1369+
self.with_loop_scope(e.id, |this| this.expr_break_alloc(e_span, ThinVec::new()));
1370+
let pat = self.pat_none(e_span);
13741371
self.arm(pat, break_expr)
13751372
};
13761373

@@ -1416,10 +1413,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
14161413

14171414
let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
14181415
let body_expr = self.expr_block(body_block, ThinVec::new());
1419-
let body_stmt = self.stmt_expr(body.span, body_expr);
1416+
let body_stmt = self.stmt_expr(body_block.span, body_expr);
14201417

14211418
let loop_block = self.block_all(
1422-
e.span,
1419+
e_span,
14231420
arena_vec![self; next_let, match_stmt, pat_let, body_stmt],
14241421
None,
14251422
);
@@ -1429,7 +1426,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
14291426
loop_block,
14301427
self.lower_label(opt_label),
14311428
hir::LoopSource::ForLoop,
1432-
self.lower_span(e.span.with_hi(orig_head_span.hi())),
1429+
self.lower_span(e_span.with_hi(head.span.hi())),
14331430
);
14341431
let loop_expr = self.arena.alloc(hir::Expr {
14351432
hir_id: self.lower_node_id(e.id),
@@ -1442,7 +1439,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
14421439

14431440
let into_iter_span = self.mark_span_with_reason(
14441441
DesugaringKind::ForLoop(ForLoopLoc::IntoIter),
1445-
orig_head_span,
1442+
head.span,
14461443
None,
14471444
);
14481445

@@ -1458,7 +1455,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
14581455
// #82462: to correctly diagnose borrow errors, the block that contains
14591456
// the iter expr needs to have a span that covers the loop body.
14601457
let desugared_full_span =
1461-
self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), e.span, None);
1458+
self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), e_span, None);
14621459

14631460
let match_expr = self.arena.alloc(self.expr_match(
14641461
desugared_full_span,

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use rustc_middle::mir::{
1111
};
1212
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
1313
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
14-
use rustc_span::source_map::DesugaringKind;
1514
use rustc_span::symbol::sym;
1615
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
1716
use rustc_trait_selection::infer::InferCtxtExt;
@@ -247,6 +246,36 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
247246
place_name, partially_str, loop_message
248247
),
249248
);
249+
let sess = self.infcx.tcx.sess;
250+
let ty = used_place.ty(self.body, self.infcx.tcx).ty;
251+
// If we have a `&mut` ref, we need to reborrow.
252+
if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
253+
// If we are in a loop this will be suggested later.
254+
if !is_loop_move {
255+
err.span_suggestion_verbose(
256+
move_span.shrink_to_lo(),
257+
&format!(
258+
"consider creating a fresh reborrow of {} here",
259+
self.describe_place(moved_place.as_ref())
260+
.map(|n| format!("`{}`", n))
261+
.unwrap_or_else(
262+
|| "the mutable reference".to_string()
263+
),
264+
),
265+
"&mut *".to_string(),
266+
Applicability::MachineApplicable,
267+
);
268+
}
269+
} else if let Ok(snippet) =
270+
sess.source_map().span_to_snippet(move_span)
271+
{
272+
err.span_suggestion(
273+
move_span,
274+
"consider borrowing to avoid moving into the for loop",
275+
format!("&{}", snippet),
276+
Applicability::MaybeIncorrect,
277+
);
278+
}
250279
} else {
251280
err.span_label(
252281
fn_call_span,
@@ -315,35 +344,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
315344
in_pattern = true;
316345
}
317346
}
318-
319-
if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
320-
let sess = self.infcx.tcx.sess;
321-
let ty = used_place.ty(self.body, self.infcx.tcx).ty;
322-
// If we have a `&mut` ref, we need to reborrow.
323-
if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
324-
// If we are in a loop this will be suggested later.
325-
if !is_loop_move {
326-
err.span_suggestion_verbose(
327-
move_span.shrink_to_lo(),
328-
&format!(
329-
"consider creating a fresh reborrow of {} here",
330-
self.describe_place(moved_place.as_ref())
331-
.map(|n| format!("`{}`", n))
332-
.unwrap_or_else(|| "the mutable reference".to_string()),
333-
),
334-
"&mut *".to_string(),
335-
Applicability::MachineApplicable,
336-
);
337-
}
338-
} else if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
339-
err.span_suggestion(
340-
move_span,
341-
"consider borrowing to avoid moving into the for loop",
342-
format!("&{}", snippet),
343-
Applicability::MaybeIncorrect,
344-
);
345-
}
346-
}
347347
}
348348

349349
use_spans.var_span_label_path_only(

compiler/rustc_borrowck/src/diagnostics/move_errors.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,10 @@ use rustc_middle::ty;
55
use rustc_mir_dataflow::move_paths::{
66
IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex,
77
};
8-
use rustc_span::source_map::DesugaringKind;
98
use rustc_span::{sym, Span, DUMMY_SP};
109
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
1110

12-
use crate::diagnostics::UseSpans;
11+
use crate::diagnostics::{FnSelfUseKind, UseSpans};
1312
use crate::prefixes::PrefixSet;
1413
use crate::MirBorrowckCtxt;
1514

@@ -400,19 +399,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
400399
| ty::Opaque(def_id, _) => def_id,
401400
_ => return err,
402401
};
403-
let is_option = self.infcx.tcx.is_diagnostic_item(sym::Option, def_id);
404-
let is_result = self.infcx.tcx.is_diagnostic_item(sym::Result, def_id);
405-
if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) {
402+
let diag_name = self.infcx.tcx.get_diagnostic_name(def_id);
403+
if matches!(diag_name, Some(sym::Option | sym::Result))
404+
&& use_spans.map_or(true, |v| !v.for_closure())
405+
{
406406
err.span_suggestion_verbose(
407407
span.shrink_to_hi(),
408-
&format!(
409-
"consider borrowing the `{}`'s content",
410-
if is_option { "Option" } else { "Result" }
411-
),
408+
&format!("consider borrowing the `{}`'s content", diag_name.unwrap()),
412409
".as_ref()".to_string(),
413410
Applicability::MaybeIncorrect,
414411
);
415-
} else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_))) {
412+
} else if let Some(UseSpans::FnSelfUse {
413+
kind: FnSelfUseKind::Normal { implicit_into_iter: true, .. },
414+
..
415+
}) = use_spans
416+
{
416417
let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
417418
Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| {
418419
type_known_to_meet_bound_modulo_regions(

compiler/rustc_lint/src/array_into_iter.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,8 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
134134
Applicability::MachineApplicable,
135135
);
136136
if self.for_expr_span == expr.span {
137-
let expr_span = expr.span.ctxt().outer_expn_data().call_site;
138137
diag.span_suggestion(
139-
receiver_arg.span.shrink_to_hi().to(expr_span.shrink_to_hi()),
138+
receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
140139
"or remove `.into_iter()` to iterate by value",
141140
String::new(),
142141
Applicability::MaybeIncorrect,

src/test/incremental/hashes/for_loops.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ pub fn change_iteration_variable_pattern() {
8383
#[cfg(not(any(cfail1,cfail4)))]
8484
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")]
8585
#[rustc_clean(cfg="cfail3")]
86-
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck, promoted_mir")]
86+
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck")]
8787
#[rustc_clean(cfg="cfail6")]
8888
pub fn change_iteration_variable_pattern() {
8989
let mut _x = 0;
@@ -108,7 +108,7 @@ pub fn change_iterable() {
108108
#[cfg(not(any(cfail1,cfail4)))]
109109
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, promoted_mir")]
110110
#[rustc_clean(cfg="cfail3")]
111-
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, promoted_mir, optimized_mir")]
111+
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, promoted_mir")]
112112
#[rustc_clean(cfg="cfail6")]
113113
pub fn change_iterable() {
114114
let mut _x = 0;
@@ -183,7 +183,7 @@ pub fn add_loop_label_to_break() {
183183
#[cfg(not(any(cfail1,cfail4)))]
184184
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
185185
#[rustc_clean(cfg="cfail3")]
186-
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")]
186+
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
187187
#[rustc_clean(cfg="cfail6")]
188188
pub fn add_loop_label_to_break() {
189189
let mut _x = 0;
@@ -237,7 +237,7 @@ pub fn add_loop_label_to_continue() {
237237
#[cfg(not(any(cfail1,cfail4)))]
238238
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
239239
#[rustc_clean(cfg="cfail3")]
240-
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")]
240+
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
241241
#[rustc_clean(cfg="cfail6")]
242242
pub fn add_loop_label_to_continue() {
243243
let mut _x = 0;

src/tools/clippy/clippy_lints/src/vec.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
6363
if is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(arg)));
6464
then {
6565
// report the error around the `vec!` not inside `<std macros>:`
66-
let span = arg.span
67-
.ctxt()
68-
.outer_expn_data()
69-
.call_site
70-
.ctxt()
71-
.outer_expn_data()
72-
.call_site;
66+
let span = arg.span.ctxt().outer_expn_data().call_site;
7367
self.check_vec_macro(cx, &vec_args, Mutability::Not, span);
7468
}
7569
}

0 commit comments

Comments
 (0)