about summary refs log tree commit diff
diff options
context:
space:
mode:
authorStuart Cook <Zalathar@users.noreply.github.com>2025-05-09 16:25:03 +1000
committerGitHub <noreply@github.com>2025-05-09 16:25:03 +1000
commitb165a4c2809a610a52bcbaae28cd4989ff684a1e (patch)
treea9d4ab8427208bc9ccc05022fefcec7e3da380b6
parentc8b7f32434c0306db5c1b974ee43443746098a92 (diff)
parent88c1796384cca81ca80e728d45f6673f601493ff (diff)
downloadrust-b165a4c2809a610a52bcbaae28cd4989ff684a1e.tar.gz
rust-b165a4c2809a610a52bcbaae28cd4989ff684a1e.zip
Rollup merge of #140801 - xizheyin:issue-140747, r=SparrowLii
Use span before macro expansion in lint for-loops-over-falibles

Fixes #140747

I think there are going to be a lot of cases where macros are expanded in the compiler resulting in span offsets, and I'd like to know how that's typically handled. Does it have to be handled specially every time?
-rw-r--r--compiler/rustc_lint/src/for_loops_over_fallibles.rs12
-rw-r--r--tests/ui/lint/for-loops-over-falibles/macro-issue-140747.rs10
-rw-r--r--tests/ui/lint/for-loops-over-falibles/macro-issue-140747.stderr24
3 files changed, 41 insertions, 5 deletions
diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
index 757fc1f58bd..a56b753bda7 100644
--- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs
+++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
@@ -49,6 +49,8 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         let Some((pat, arg)) = extract_for_loop(expr) else { return };
 
+        let arg_span = arg.span.source_callsite();
+
         let ty = cx.typeck_results().expr_ty(arg);
 
         let (adt, args, ref_mutability) = match ty.kind() {
@@ -78,27 +80,27 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles {
             && let Ok(recv_snip) = cx.sess().source_map().span_to_snippet(recv.span)
         {
             ForLoopsOverFalliblesLoopSub::RemoveNext {
-                suggestion: recv.span.between(arg.span.shrink_to_hi()),
+                suggestion: recv.span.between(arg_span.shrink_to_hi()),
                 recv_snip,
             }
         } else {
             ForLoopsOverFalliblesLoopSub::UseWhileLet {
                 start_span: expr.span.with_hi(pat.span.lo()),
-                end_span: pat.span.between(arg.span),
+                end_span: pat.span.between(arg_span),
                 var,
             }
         };
         let question_mark = suggest_question_mark(cx, adt, args, expr.span)
-            .then(|| ForLoopsOverFalliblesQuestionMark { suggestion: arg.span.shrink_to_hi() });
+            .then(|| ForLoopsOverFalliblesQuestionMark { suggestion: arg_span.shrink_to_hi() });
         let suggestion = ForLoopsOverFalliblesSuggestion {
             var,
             start_span: expr.span.with_hi(pat.span.lo()),
-            end_span: pat.span.between(arg.span),
+            end_span: pat.span.between(arg_span),
         };
 
         cx.emit_span_lint(
             FOR_LOOPS_OVER_FALLIBLES,
-            arg.span,
+            arg_span,
             ForLoopsOverFalliblesDiag { article, ref_prefix, ty, sub, question_mark, suggestion },
         );
     }
diff --git a/tests/ui/lint/for-loops-over-falibles/macro-issue-140747.rs b/tests/ui/lint/for-loops-over-falibles/macro-issue-140747.rs
new file mode 100644
index 00000000000..33a89ced963
--- /dev/null
+++ b/tests/ui/lint/for-loops-over-falibles/macro-issue-140747.rs
@@ -0,0 +1,10 @@
+#![forbid(for_loops_over_fallibles)]
+
+fn main() {
+    macro_rules! x {
+        () => {
+            None::<i32>
+        };
+    }
+    for _ in x! {} {} //~ ERROR for loop over an `Option`. This is more readably written as an `if let` statement [for_loops_over_fallibles]
+}
diff --git a/tests/ui/lint/for-loops-over-falibles/macro-issue-140747.stderr b/tests/ui/lint/for-loops-over-falibles/macro-issue-140747.stderr
new file mode 100644
index 00000000000..550d26045fb
--- /dev/null
+++ b/tests/ui/lint/for-loops-over-falibles/macro-issue-140747.stderr
@@ -0,0 +1,24 @@
+error: for loop over an `Option`. This is more readably written as an `if let` statement
+  --> $DIR/macro-issue-140747.rs:9:14
+   |
+LL |     for _ in x! {} {}
+   |              ^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/macro-issue-140747.rs:1:11
+   |
+LL | #![forbid(for_loops_over_fallibles)]
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^
+help: to check pattern in a loop use `while let`
+   |
+LL -     for _ in x! {} {}
+LL +     while let Some(_) = x! {} {}
+   |
+help: consider using `if let` to clear intent
+   |
+LL -     for _ in x! {} {}
+LL +     if let Some(_) = x! {} {}
+   |
+
+error: aborting due to 1 previous error
+