Skip to content

Commit

Permalink
Auto merge of #87956 - m-ou-se:closure-migration-macro-body, r=Aaron1011
Browse files Browse the repository at this point in the history
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) };
  |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~
```
  • Loading branch information
bors committed Aug 13, 2021
2 parents 04c9901 + 26c590d commit 2fc3c69
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 6 deletions.
22 changes: 16 additions & 6 deletions compiler/rustc_typeck/src/check/upvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand All @@ -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!(
Expand All @@ -677,7 +687,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);

diagnostics_builder.span_suggestion(
closure_body_span,
span,
&diagnostic_msg,
sugg,
app,
Expand Down
16 changes: 16 additions & 0 deletions src/test/ui/closures/2229_closure_analysis/migrations/macro.fixed
Original file line number Diff line number Diff line change
@@ -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
16 changes: 16 additions & 0 deletions src/test/ui/closures/2229_closure_analysis/migrations/macro.rs
Original file line number Diff line number Diff line change
@@ -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
24 changes: 24 additions & 0 deletions src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 2fc3c69

Please sign in to comment.