Skip to content

Commit 2fc3c69

Browse files
committed
Auto merge of #87956 - m-ou-se:closure-migration-macro-body, r=Aaron1011
Fix closure migration suggestion when the body is a macro. Fixes #87955 Before: ``` warning: changes to closure capture in Rust 2021 will affect drop order --> src/main.rs:5:13 | 5 | let _ = || panic!(a.0); | ^^^^^^^^^^---^ | | | in Rust 2018, closure captures all of `a`, but in Rust 2021, it only captures `a.0` 6 | } | - in Rust 2018, `a` would be dropped here, but in Rust 2021, only `a.0` would be dropped here alongside the closure | help: add a dummy let to cause `a` to be fully captured | 20~ ($msg:expr $(,)?) => ({ let _ = &a; 21+ $crate::rt::begin_panic($msg) 22~ }), | ``` After: ``` warning: changes to closure capture in Rust 2021 will affect drop order --> src/main.rs:5:13 | 5 | let _ = || panic!(a.0); | ^^^^^^^^^^---^ | | | in Rust 2018, closure captures all of `a`, but in Rust 2021, it only captures `a.0` 6 | } | - in Rust 2018, `a` would be dropped here, but in Rust 2021, only `a.0` would be dropped here alongside the closure | help: add a dummy let to cause `a` to be fully captured | 5 | let _ = || { let _ = &a; panic!(a.0) }; | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ```
2 parents 04c9901 + 26c590d commit 2fc3c69

File tree

4 files changed

+72
-6
lines changed

4 files changed

+72
-6
lines changed

Diff for: compiler/rustc_typeck/src/check/upvar.rs

+16-6
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ use rustc_middle::ty::{
4747
};
4848
use rustc_session::lint;
4949
use rustc_span::sym;
50-
use rustc_span::{MultiSpan, Span, Symbol};
50+
use rustc_span::{MultiSpan, Span, Symbol, DUMMY_SP};
5151
use rustc_trait_selection::infer::InferCtxtExt;
5252

5353
use rustc_data_structures::stable_map::FxHashMap;
@@ -644,8 +644,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
644644
}
645645
}
646646
diagnostics_builder.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>");
647-
let closure_body_span = self.tcx.hir().span(body_id.hir_id);
648-
let (sugg, app) =
647+
648+
let mut closure_body_span = self.tcx.hir().span(body_id.hir_id);
649+
650+
// If the body was entirely expanded from a macro
651+
// invocation, i.e. the body is not contained inside the
652+
// closure span, then we walk up the expansion until we
653+
// find the span before the expansion.
654+
while !closure_body_span.is_dummy() && !closure_span.contains(closure_body_span) {
655+
closure_body_span = closure_body_span.parent().unwrap_or(DUMMY_SP);
656+
}
657+
658+
let (span, sugg, app) =
649659
match self.tcx.sess.source_map().span_to_snippet(closure_body_span) {
650660
Ok(s) => {
651661
let trimmed = s.trim_start();
@@ -666,9 +676,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
666676
} else {
667677
format!("{{ {}; {} }}", migration_string, s)
668678
};
669-
(sugg, Applicability::MachineApplicable)
679+
(closure_body_span, sugg, Applicability::MachineApplicable)
670680
}
671-
Err(_) => (migration_string.clone(), Applicability::HasPlaceholders),
681+
Err(_) => (closure_span, migration_string.clone(), Applicability::HasPlaceholders),
672682
};
673683

674684
let diagnostic_msg = format!(
@@ -677,7 +687,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
677687
);
678688

679689
diagnostics_builder.span_suggestion(
680-
closure_body_span,
690+
span,
681691
&diagnostic_msg,
682692
sugg,
683693
app,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// run-rustfix
2+
3+
// See https://github.com/rust-lang/rust/issues/87955
4+
5+
#![deny(rust_2021_incompatible_closure_captures)]
6+
//~^ NOTE: the lint level is defined here
7+
8+
fn main() {
9+
let a = ("hey".to_string(), "123".to_string());
10+
let _ = || { let _ = &a; dbg!(a.0) };
11+
//~^ ERROR: drop order
12+
//~| NOTE: only captures `a.0`
13+
//~| NOTE: for more information, see
14+
//~| HELP: add a dummy let to cause `a` to be fully captured
15+
}
16+
//~^ NOTE: dropped here
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// run-rustfix
2+
3+
// See https://github.com/rust-lang/rust/issues/87955
4+
5+
#![deny(rust_2021_incompatible_closure_captures)]
6+
//~^ NOTE: the lint level is defined here
7+
8+
fn main() {
9+
let a = ("hey".to_string(), "123".to_string());
10+
let _ = || dbg!(a.0);
11+
//~^ ERROR: drop order
12+
//~| NOTE: only captures `a.0`
13+
//~| NOTE: for more information, see
14+
//~| HELP: add a dummy let to cause `a` to be fully captured
15+
}
16+
//~^ NOTE: dropped here
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error: changes to closure capture in Rust 2021 will affect drop order
2+
--> $DIR/macro.rs:10:13
3+
|
4+
LL | let _ = || dbg!(a.0);
5+
| ^^^^^^^^---^
6+
| |
7+
| in Rust 2018, closure captures all of `a`, but in Rust 2021, it only captures `a.0`
8+
...
9+
LL | }
10+
| - in Rust 2018, `a` would be dropped here, but in Rust 2021, only `a.0` would be dropped here alongside the closure
11+
|
12+
note: the lint level is defined here
13+
--> $DIR/macro.rs:5:9
14+
|
15+
LL | #![deny(rust_2021_incompatible_closure_captures)]
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
17+
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
18+
help: add a dummy let to cause `a` to be fully captured
19+
|
20+
LL | let _ = || { let _ = &a; dbg!(a.0) };
21+
| ~~~~~~~~~~~~~~~~~~~~~~~~~
22+
23+
error: aborting due to previous error
24+

0 commit comments

Comments
 (0)