Auto merge of #87956 - m-ou-se:closure-migration-macro-body, r=Aaron1011

Fix closure migration suggestion when the body is a macro.

Fixes https://github.com/rust-lang/rust/issues/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) };
  |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~
```
This commit is contained in:
bors 2021-08-13 08:31:26 +00:00
commit 2fc3c69e54
4 changed files with 72 additions and 6 deletions

View File

@ -47,7 +47,7 @@ use rustc_middle::ty::{
};
use rustc_session::lint;
use rustc_span::sym;
use rustc_span::{MultiSpan, Span, Symbol};
use rustc_span::{MultiSpan, Span, Symbol, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_data_structures::stable_map::FxHashMap;
@ -644,8 +644,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
diagnostics_builder.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>");
let closure_body_span = self.tcx.hir().span(body_id.hir_id);
let (sugg, app) =
let mut closure_body_span = self.tcx.hir().span(body_id.hir_id);
// If the body was entirely expanded from a macro
// invocation, i.e. the body is not contained inside the
// closure span, then we walk up the expansion until we
// find the span before the expansion.
while !closure_body_span.is_dummy() && !closure_span.contains(closure_body_span) {
closure_body_span = closure_body_span.parent().unwrap_or(DUMMY_SP);
}
let (span, sugg, app) =
match self.tcx.sess.source_map().span_to_snippet(closure_body_span) {
Ok(s) => {
let trimmed = s.trim_start();
@ -666,9 +676,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
format!("{{ {}; {} }}", migration_string, s)
};
(sugg, Applicability::MachineApplicable)
(closure_body_span, sugg, Applicability::MachineApplicable)
}
Err(_) => (migration_string.clone(), Applicability::HasPlaceholders),
Err(_) => (closure_span, migration_string.clone(), Applicability::HasPlaceholders),
};
let diagnostic_msg = format!(
@ -677,7 +687,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
diagnostics_builder.span_suggestion(
closure_body_span,
span,
&diagnostic_msg,
sugg,
app,

View File

@ -0,0 +1,16 @@
// run-rustfix
// See https://github.com/rust-lang/rust/issues/87955
#![deny(rust_2021_incompatible_closure_captures)]
//~^ NOTE: the lint level is defined here
fn main() {
let a = ("hey".to_string(), "123".to_string());
let _ = || { let _ = &a; dbg!(a.0) };
//~^ ERROR: drop order
//~| NOTE: only captures `a.0`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `a` to be fully captured
}
//~^ NOTE: dropped here

View File

@ -0,0 +1,16 @@
// run-rustfix
// See https://github.com/rust-lang/rust/issues/87955
#![deny(rust_2021_incompatible_closure_captures)]
//~^ NOTE: the lint level is defined here
fn main() {
let a = ("hey".to_string(), "123".to_string());
let _ = || dbg!(a.0);
//~^ ERROR: drop order
//~| NOTE: only captures `a.0`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `a` to be fully captured
}
//~^ NOTE: dropped here

View File

@ -0,0 +1,24 @@
error: changes to closure capture in Rust 2021 will affect drop order
--> $DIR/macro.rs:10:13
|
LL | let _ = || dbg!(a.0);
| ^^^^^^^^---^
| |
| in Rust 2018, closure captures all of `a`, but in Rust 2021, it only captures `a.0`
...
LL | }
| - in Rust 2018, `a` would be dropped here, but in Rust 2021, only `a.0` would be dropped here alongside the closure
|
note: the lint level is defined here
--> $DIR/macro.rs:5:9
|
LL | #![deny(rust_2021_incompatible_closure_captures)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
help: add a dummy let to cause `a` to be fully captured
|
LL | let _ = || { let _ = &a; dbg!(a.0) };
| ~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error