diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index cd93cbbe965..bbe843f468b 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -495,10 +495,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let closure_body_span = self.tcx.hir().span(body_id.hir_id); let (sugg, app) = match self.tcx.sess.source_map().span_to_snippet(closure_body_span) { - Ok(s) => ( - format!("{{ {}; {} }}", migration_string, s), - Applicability::MachineApplicable, - ), + Ok(s) => { + let trimmed = s.trim_start(); + + // If the closure contains a block then replace the opening brace + // with "{ let _ = (..); " + let sugg = if let Some('{') = trimmed.chars().next() { + format!("{{ {}; {}", migration_string, &trimmed[1..]) + } else { + format!("{{ {}; {} }}", migration_string, s) + }; + (sugg, Applicability::MachineApplicable) + } Err(_) => (migration_string.clone(), Applicability::HasPlaceholders), }; diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed index 3e346078915..0f4c7dcb0df 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed @@ -12,14 +12,14 @@ fn test1_all_need_migration() { let t1 = (String::new(), String::new()); let t2 = (String::new(), String::new()); - let c = || { let _ = (&t, &t1, &t2); { + let c = || { let _ = (&t, &t1, &t2); //~^ ERROR: drop order affected for closure because of `capture_disjoint_fields` //~| HELP:` let _ = (&t, &t1, &t2)` causes `t`, `t1`, `t2` to be fully captured let _t = t.0; let _t1 = t1.0; let _t2 = t2.0; - } }; + }; c(); } @@ -31,13 +31,13 @@ fn test2_only_precise_paths_need_migration() { let t1 = (String::new(), String::new()); let t2 = (String::new(), String::new()); - let c = || { let _ = (&t, &t1); { + let c = || { let _ = (&t, &t1); //~^ ERROR: drop order affected for closure because of `capture_disjoint_fields` //~| HELP:` let _ = (&t, &t1)` causes `t`, `t1` to be fully captured let _t = t.0; let _t1 = t1.0; let _t2 = t2; - } }; + }; c(); } @@ -47,12 +47,12 @@ fn test2_only_precise_paths_need_migration() { fn test3_only_by_value_need_migration() { let t = (String::new(), String::new()); let t1 = (String::new(), String::new()); - let c = || { let _ = &t; { + let c = || { let _ = &t; //~^ ERROR: drop order affected for closure because of `capture_disjoint_fields` //~| HELP: `let _ = &t` causes `t` to be fully captured let _t = t.0; println!("{}", t1.1); - } }; + }; c(); } @@ -65,12 +65,12 @@ fn test4_only_non_copy_types_need_migration() { // `t1` is Copy because all of its elements are Copy let t1 = (0i32, 0i32); - let c = || { let _ = &t; { + let c = || { let _ = &t; //~^ ERROR: drop order affected for closure because of `capture_disjoint_fields` //~| HELP: `let _ = &t` causes `t` to be fully captured let _t = t.0; let _t1 = t1.0; - } }; + }; c(); } @@ -83,12 +83,12 @@ fn test5_only_drop_types_need_migration() { // `s` doesn't implement Drop or any elements within it, and doesn't need migration let s = S(0i32, 0i32); - let c = || { let _ = &t; { + let c = || { let _ = &t; //~^ ERROR: drop order affected for closure because of `capture_disjoint_fields` //~| HELP: `let _ = &t` causes `t` to be fully captured let _t = t.0; let _s = s.0; - } }; + }; c(); } @@ -98,11 +98,11 @@ fn test5_only_drop_types_need_migration() { fn test6_move_closures_non_copy_types_might_need_migration() { let t = (String::new(), String::new()); let t1 = (String::new(), String::new()); - let c = move || { let _ = (&t1, &t); { + let c = move || { let _ = (&t1, &t); //~^ ERROR: drop order affected for closure because of `capture_disjoint_fields` //~| HELP: `let _ = (&t1, &t)` causes `t1`, `t` to be fully captured println!("{} {}", t1.1, t.1); - } }; + }; c(); } @@ -113,11 +113,11 @@ fn test6_move_closures_non_copy_types_might_need_migration() { fn test7_drop_non_drop_aggregate_need_migration() { let t = (String::new(), String::new(), 0i32); - let c = || { let _ = &t; { + let c = || { let _ = &t; //~^ ERROR: drop order affected for closure because of `capture_disjoint_fields` //~| HELP: `let _ = &t` causes `t` to be fully captured let _t = t.0; - } }; + }; c(); } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr index 925df1160c8..253a906a0ec 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr @@ -18,7 +18,7 @@ LL | #![deny(disjoint_capture_drop_reorder)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `let _ = (&t, &t1, &t2)` causes `t`, `t1`, `t2` to be fully captured | -LL | let c = || { let _ = (&t, &t1, &t2); { +LL | let c = || { let _ = (&t, &t1, &t2); LL | LL | LL | @@ -41,7 +41,7 @@ LL | | }; | help: `let _ = (&t, &t1)` causes `t`, `t1` to be fully captured | -LL | let c = || { let _ = (&t, &t1); { +LL | let c = || { let _ = (&t, &t1); LL | LL | LL | let _t = t.0; @@ -63,12 +63,12 @@ LL | | }; | help: `let _ = &t` causes `t` to be fully captured | -LL | let c = || { let _ = &t; { +LL | let c = || { let _ = &t; LL | LL | LL | let _t = t.0; LL | println!("{}", t1.1); -LL | } }; +LL | }; | error: drop order affected for closure because of `capture_disjoint_fields` @@ -85,12 +85,12 @@ LL | | }; | help: `let _ = &t` causes `t` to be fully captured | -LL | let c = || { let _ = &t; { +LL | let c = || { let _ = &t; LL | LL | LL | let _t = t.0; LL | let _t1 = t1.0; -LL | } }; +LL | }; | error: drop order affected for closure because of `capture_disjoint_fields` @@ -107,12 +107,12 @@ LL | | }; | help: `let _ = &t` causes `t` to be fully captured | -LL | let c = || { let _ = &t; { +LL | let c = || { let _ = &t; LL | LL | LL | let _t = t.0; LL | let _s = s.0; -LL | } }; +LL | }; | error: drop order affected for closure because of `capture_disjoint_fields` @@ -128,11 +128,11 @@ LL | | }; | help: `let _ = (&t1, &t)` causes `t1`, `t` to be fully captured | -LL | let c = move || { let _ = (&t1, &t); { +LL | let c = move || { let _ = (&t1, &t); LL | LL | LL | println!("{} {}", t1.1, t.1); -LL | } }; +LL | }; | error: drop order affected for closure because of `capture_disjoint_fields` @@ -148,11 +148,11 @@ LL | | }; | help: `let _ = &t` causes `t` to be fully captured | -LL | let c = || { let _ = &t; { +LL | let c = || { let _ = &t; LL | LL | LL | let _t = t.0; -LL | } }; +LL | }; | error: aborting due to 7 previous errors diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.fixed new file mode 100644 index 00000000000..f17fab8e81f --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.fixed @@ -0,0 +1,40 @@ +// run-rustfix +#![deny(disjoint_capture_drop_reorder)] +//~^ NOTE: the lint level is defined here + +// Test the two possible cases for automated migartion using rustfix +// - Closure contains a block i.e. `|| { .. };` +// - Closure contains just an expr `|| ..;` + +#[derive(Debug)] +struct Foo(i32); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + +fn closure_contains_block() { + let t = (Foo(0), Foo(0)); + let c = || { let _ = &t; + //~^ ERROR: drop order affected for closure because of `capture_disjoint_fields` + //~| HELP: `let _ = &t` causes `t` to be fully captured + let _t = t.0; + }; + + c(); +} + +fn closure_doesnt_contain_block() { + let t = (Foo(0), Foo(0)); + let c = || { let _ = &t; t.0 }; + //~^ ERROR: drop order affected for closure because of `capture_disjoint_fields` + //~| HELP: `let _ = &t` causes `t` to be fully captured + + c(); +} + +fn main() { + closure_contains_block(); + closure_doesnt_contain_block(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.rs b/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.rs new file mode 100644 index 00000000000..33aff10c520 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.rs @@ -0,0 +1,40 @@ +// run-rustfix +#![deny(disjoint_capture_drop_reorder)] +//~^ NOTE: the lint level is defined here + +// Test the two possible cases for automated migartion using rustfix +// - Closure contains a block i.e. `|| { .. };` +// - Closure contains just an expr `|| ..;` + +#[derive(Debug)] +struct Foo(i32); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + +fn closure_contains_block() { + let t = (Foo(0), Foo(0)); + let c = || { + //~^ ERROR: drop order affected for closure because of `capture_disjoint_fields` + //~| HELP: `let _ = &t` causes `t` to be fully captured + let _t = t.0; + }; + + c(); +} + +fn closure_doesnt_contain_block() { + let t = (Foo(0), Foo(0)); + let c = || t.0; + //~^ ERROR: drop order affected for closure because of `capture_disjoint_fields` + //~| HELP: `let _ = &t` causes `t` to be fully captured + + c(); +} + +fn main() { + closure_contains_block(); + closure_doesnt_contain_block(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr new file mode 100644 index 00000000000..611fbc4fff3 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr @@ -0,0 +1,38 @@ +error: drop order affected for closure because of `capture_disjoint_fields` + --> $DIR/migrations_rustfix.rs:19:13 + | +LL | let c = || { + | _____________^ +LL | | +LL | | +LL | | let _t = t.0; +LL | | }; + | |_____^ + | +note: the lint level is defined here + --> $DIR/migrations_rustfix.rs:2:9 + | +LL | #![deny(disjoint_capture_drop_reorder)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: `let _ = &t` causes `t` to be fully captured + | +LL | let c = || { let _ = &t; +LL | +LL | +LL | let _t = t.0; +LL | }; + | + +error: drop order affected for closure because of `capture_disjoint_fields` + --> $DIR/migrations_rustfix.rs:30:13 + | +LL | let c = || t.0; + | ^^^^^^ + | +help: `let _ = &t` causes `t` to be fully captured + | +LL | let c = || { let _ = &t; t.0 }; + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/precise.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/precise.fixed index 53793be8a69..06932c1ae64 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/precise.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/precise.fixed @@ -16,12 +16,12 @@ struct ConstainsDropField(Foo, Foo); fn test_precise_analysis_drop_paths_not_captured_by_move() { let t = ConstainsDropField(Foo(10), Foo(20)); - let c = || { let _ = &t; { + let c = || { let _ = &t; //~^ ERROR: drop order affected for closure because of `capture_disjoint_fields` //~| HELP: `let _ = &t` causes `t` to be fully captured let _t = t.0; let _t = &t.1; - } }; + }; c(); } @@ -39,13 +39,13 @@ struct U(T, T); fn test_precise_analysis_long_path_missing() { let u = U(T(S, S), T(S, S)); - let c = || { let _ = &u; { + let c = || { let _ = &u; //~^ ERROR: drop order affected for closure because of `capture_disjoint_fields` //~| HELP: `let _ = &u` causes `u` to be fully captured let _x = u.0.0; let _x = u.0.1; let _x = u.1.0; - } }; + }; c(); } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/precise.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/precise.stderr index 4cd75a15adb..fcfd08d61e0 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/precise.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/precise.stderr @@ -17,12 +17,12 @@ LL | #![deny(disjoint_capture_drop_reorder)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `let _ = &t` causes `t` to be fully captured | -LL | let c = || { let _ = &t; { +LL | let c = || { let _ = &t; LL | LL | LL | let _t = t.0; LL | let _t = &t.1; -LL | } }; +LL | }; | error: drop order affected for closure because of `capture_disjoint_fields` @@ -40,7 +40,7 @@ LL | | }; | help: `let _ = &u` causes `u` to be fully captured | -LL | let c = || { let _ = &u; { +LL | let c = || { let _ = &u; LL | LL | LL | let _x = u.0.0; diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed index 82b9299c1f4..b44624be5f9 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed @@ -22,13 +22,13 @@ fn test1_all_need_migration() { let t1 = (Foo(0), Foo(0)); let t2 = (Foo(0), Foo(0)); - let c = || { let _ = (&t, &t1, &t2); { + let c = || { let _ = (&t, &t1, &t2); //~^ ERROR: drop order affected for closure because of `capture_disjoint_fields` //~| HELP:` let _ = (&t, &t1, &t2)` causes `t`, `t1`, `t2` to be fully captured let _t = t.0; let _t1 = t1.0; let _t2 = t2.0; - } }; + }; c(); } @@ -40,13 +40,13 @@ fn test2_only_precise_paths_need_migration() { let t1 = (Foo(0), Foo(0)); let t2 = (Foo(0), Foo(0)); - let c = || { let _ = (&t, &t1); { + let c = || { let _ = (&t, &t1); //~^ ERROR: drop order affected for closure because of `capture_disjoint_fields` //~| HELP:` let _ = (&t, &t1)` causes `t`, `t1` to be fully captured let _t = t.0; let _t1 = t1.0; let _t2 = t2; - } }; + }; c(); } @@ -56,12 +56,12 @@ fn test2_only_precise_paths_need_migration() { fn test3_only_by_value_need_migration() { let t = (Foo(0), Foo(0)); let t1 = (Foo(0), Foo(0)); - let c = || { let _ = &t; { + let c = || { let _ = &t; //~^ ERROR: drop order affected for closure because of `capture_disjoint_fields` //~| HELP: `let _ = &t` causes `t` to be fully captured let _t = t.0; println!("{:?}", t1.1); - } }; + }; c(); } @@ -73,11 +73,11 @@ fn test3_only_by_value_need_migration() { fn test4_type_contains_drop_need_migration() { let t = ConstainsDropField(Foo(0), Foo(0)); - let c = || { let _ = &t; { + let c = || { let _ = &t; //~^ ERROR: drop order affected for closure because of `capture_disjoint_fields` //~| HELP: `let _ = &t` causes `t` to be fully captured let _t = t.0; - } }; + }; c(); } @@ -88,11 +88,11 @@ fn test4_type_contains_drop_need_migration() { fn test5_drop_non_drop_aggregate_need_migration() { let t = (Foo(0), Foo(0), 0i32); - let c = || { let _ = &t; { + let c = || { let _ = &t; //~^ ERROR: drop order affected for closure because of `capture_disjoint_fields` //~| HELP: `let _ = &t` causes `t` to be fully captured let _t = t.0; - } }; + }; c(); } @@ -101,11 +101,11 @@ fn test5_drop_non_drop_aggregate_need_migration() { fn test6_significant_insignificant_drop_aggregate_need_migration() { let t = (Foo(0), String::new()); - let c = || { let _ = &t; { + let c = || { let _ = &t; //~^ ERROR: drop order affected for closure because of `capture_disjoint_fields` //~| HELP: `let _ = &t` causes `t` to be fully captured let _t = t.1; - } }; + }; c(); } @@ -116,11 +116,11 @@ fn test7_move_closures_non_copy_types_might_need_migration() { let t = (Foo(0), Foo(0)); let t1 = (Foo(0), Foo(0), Foo(0)); - let c = move || { let _ = (&t1, &t); { + let c = move || { let _ = (&t1, &t); //~^ ERROR: drop order affected for closure because of `capture_disjoint_fields` //~| HELP: `let _ = (&t1, &t)` causes `t1`, `t` to be fully captured println!("{:?} {:?}", t1.1, t.1); - } }; + }; c(); } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr index fcf734020ce..2ca2baa9cbc 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr @@ -18,7 +18,7 @@ LL | #![deny(disjoint_capture_drop_reorder)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `let _ = (&t, &t1, &t2)` causes `t`, `t1`, `t2` to be fully captured | -LL | let c = || { let _ = (&t, &t1, &t2); { +LL | let c = || { let _ = (&t, &t1, &t2); LL | LL | LL | let _t = t.0; @@ -41,7 +41,7 @@ LL | | }; | help: `let _ = (&t, &t1)` causes `t`, `t1` to be fully captured | -LL | let c = || { let _ = (&t, &t1); { +LL | let c = || { let _ = (&t, &t1); LL | LL | LL | let _t = t.0; @@ -63,12 +63,12 @@ LL | | }; | help: `let _ = &t` causes `t` to be fully captured | -LL | let c = || { let _ = &t; { +LL | let c = || { let _ = &t; LL | LL | LL | let _t = t.0; LL | println!("{:?}", t1.1); -LL | } }; +LL | }; | error: drop order affected for closure because of `capture_disjoint_fields` @@ -84,11 +84,11 @@ LL | | }; | help: `let _ = &t` causes `t` to be fully captured | -LL | let c = || { let _ = &t; { +LL | let c = || { let _ = &t; LL | LL | LL | let _t = t.0; -LL | } }; +LL | }; | error: drop order affected for closure because of `capture_disjoint_fields` @@ -104,11 +104,11 @@ LL | | }; | help: `let _ = &t` causes `t` to be fully captured | -LL | let c = || { let _ = &t; { +LL | let c = || { let _ = &t; LL | LL | LL | let _t = t.0; -LL | } }; +LL | }; | error: drop order affected for closure because of `capture_disjoint_fields` @@ -124,11 +124,11 @@ LL | | }; | help: `let _ = &t` causes `t` to be fully captured | -LL | let c = || { let _ = &t; { +LL | let c = || { let _ = &t; LL | LL | LL | let _t = t.1; -LL | } }; +LL | }; | error: drop order affected for closure because of `capture_disjoint_fields` @@ -144,11 +144,11 @@ LL | | }; | help: `let _ = (&t1, &t)` causes `t1`, `t` to be fully captured | -LL | let c = move || { let _ = (&t1, &t); { +LL | let c = move || { let _ = (&t1, &t); LL | LL | LL | println!("{:?} {:?}", t1.1, t.1); -LL | } }; +LL | }; | error: aborting due to 7 previous errors