From 0b7ff9660f95daf752281220f48722061db60def Mon Sep 17 00:00:00 2001 From: Roxane Date: Tue, 6 Jul 2021 16:48:49 -0400 Subject: [PATCH 1/9] Add note on why the variable is not fully captured --- compiler/rustc_typeck/src/check/upvar.rs | 92 ++++++++++++------- .../migrations/auto_traits.stderr | 3 + .../migrations/insignificant_drop.fixed | 11 +++ .../migrations/insignificant_drop.rs | 11 +++ .../migrations/insignificant_drop.stderr | 58 ++++++++---- .../insignificant_drop_attr_migrations.fixed | 2 + .../insignificant_drop_attr_migrations.rs | 2 + .../insignificant_drop_attr_migrations.stderr | 14 ++- .../migrations/migrations_rustfix.fixed | 3 + .../migrations/migrations_rustfix.rs | 3 + .../migrations/migrations_rustfix.stderr | 13 ++- .../migrations/mir_calls_to_shims.stderr | 1 + .../migrations/precise.stderr | 4 + .../migrations/significant_drop.fixed | 11 +++ .../migrations/significant_drop.rs | 11 +++ .../migrations/significant_drop.stderr | 63 +++++++++---- 16 files changed, 227 insertions(+), 75 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 4d6d1da194fc6..106fea2b2f73d 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -510,6 +510,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) .as_str(), ); + for (var_hir_id, diagnostics_info) in need_migrations.iter() { + for (captured_hir_id, captured_name) in diagnostics_info.iter() { + if let Some(captured_hir_id) = captured_hir_id { + let cause_span = self.tcx.hir().span(*captured_hir_id); + diagnostics_builder.span_label(cause_span, format!("in Rust 2018, closure captures all of `{}`, but in Rust 2021, it only captures `{}`", + self.tcx.hir().name(*var_hir_id), + captured_name, + )); + } + } + } diagnostics_builder.note("for more information, see "); let closure_body_span = self.tcx.hir().span(body_id.hir_id); let (sugg, app) = @@ -579,13 +590,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { var_hir_id: hir::HirId, check_trait: Option, closure_clause: hir::CaptureBy, - ) -> bool { + ) -> Option<(Option, String)> { let root_var_min_capture_list = if let Some(root_var_min_capture_list) = min_captures.and_then(|m| m.get(&var_hir_id)) { root_var_min_capture_list } else { - return false; + return None; }; let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id)); @@ -639,10 +650,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .unwrap_or(false); if !obligation_holds_for_capture && obligation_should_hold { - return true; + return Some((capture.info.path_expr_id, capture.to_string(self.tcx))); } } - false + None } /// Figures out the list of root variables (and their types) that aren't completely @@ -660,68 +671,75 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, var_hir_id: hir::HirId, closure_clause: hir::CaptureBy, - ) -> Option> { + ) -> Option<(FxHashSet<&str>, FxHashSet<(Option, String)>)> { let tcx = self.infcx.tcx; // Check whether catpured fields also implement the trait let mut auto_trait_reasons = FxHashSet::default(); + let mut diagnostics_info = FxHashSet::default(); - if self.need_2229_migrations_for_trait( + if let Some(info) = self.need_2229_migrations_for_trait( min_captures, var_hir_id, tcx.lang_items().clone_trait(), closure_clause, ) { auto_trait_reasons.insert("`Clone`"); + diagnostics_info.insert(info); } - if self.need_2229_migrations_for_trait( + if let Some(info) = self.need_2229_migrations_for_trait( min_captures, var_hir_id, tcx.lang_items().sync_trait(), closure_clause, ) { auto_trait_reasons.insert("`Sync`"); + diagnostics_info.insert(info); } - if self.need_2229_migrations_for_trait( + if let Some(info) = self.need_2229_migrations_for_trait( min_captures, var_hir_id, tcx.get_diagnostic_item(sym::send_trait), closure_clause, ) { auto_trait_reasons.insert("`Send`"); + diagnostics_info.insert(info); } - if self.need_2229_migrations_for_trait( + if let Some(info) = self.need_2229_migrations_for_trait( min_captures, var_hir_id, tcx.lang_items().unpin_trait(), closure_clause, ) { auto_trait_reasons.insert("`Unpin`"); + diagnostics_info.insert(info); } - if self.need_2229_migrations_for_trait( + if let Some(info) = self.need_2229_migrations_for_trait( min_captures, var_hir_id, tcx.get_diagnostic_item(sym::unwind_safe_trait), closure_clause, ) { auto_trait_reasons.insert("`UnwindSafe`"); + diagnostics_info.insert(info); } - if self.need_2229_migrations_for_trait( + if let Some(info) = self.need_2229_migrations_for_trait( min_captures, var_hir_id, tcx.get_diagnostic_item(sym::ref_unwind_safe_trait), closure_clause, ) { auto_trait_reasons.insert("`RefUnwindSafe`"); + diagnostics_info.insert(info); } if auto_trait_reasons.len() > 0 { - return Some(auto_trait_reasons); + return Some((auto_trait_reasons, diagnostics_info)); } return None; @@ -746,11 +764,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, closure_clause: hir::CaptureBy, var_hir_id: hir::HirId, - ) -> bool { + ) -> Option, String)>> { let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id)); if !ty.has_significant_drop(self.tcx, self.tcx.param_env(closure_def_id.expect_local())) { - return false; + return None; } let root_var_min_capture_list = if let Some(root_var_min_capture_list) = @@ -763,21 +781,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match closure_clause { // Only migrate if closure is a move closure - hir::CaptureBy::Value => return true, + hir::CaptureBy::Value => return Some(FxHashSet::default()), hir::CaptureBy::Ref => {} } - return false; + return None; }; - let projections_list = root_var_min_capture_list - .iter() - .filter_map(|captured_place| match captured_place.info.capture_kind { + let mut projections_list = Vec::new(); + let mut diagnostics_info = FxHashSet::default(); + + for captured_place in root_var_min_capture_list.iter() { + match captured_place.info.capture_kind { // Only care about captures that are moved into the closure - ty::UpvarCapture::ByValue(..) => Some(captured_place.place.projections.as_slice()), - ty::UpvarCapture::ByRef(..) => None, - }) - .collect::>(); + ty::UpvarCapture::ByValue(..) => { + projections_list.push(captured_place.place.projections.as_slice()); + diagnostics_info.insert(( + captured_place.info.path_expr_id, + captured_place.to_string(self.tcx), + )); + } + ty::UpvarCapture::ByRef(..) => {} + } + } let is_moved = !projections_list.is_empty(); @@ -793,10 +819,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { projections_list, ) { - return true; + return Some(diagnostics_info); } - return false; + return None; } /// Figures out the list of root variables (and their types) that aren't completely @@ -820,7 +846,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { closure_span: Span, closure_clause: hir::CaptureBy, min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, - ) -> (Vec, String) { + ) -> (Vec<(hir::HirId, FxHashSet<(Option, String)>)>, String) { let upvars = if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { upvars } else { @@ -834,14 +860,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Perform auto-trait analysis for (&var_hir_id, _) in upvars.iter() { let mut need_migration = false; - if let Some(trait_migration_cause) = + let mut responsible_captured_hir_ids = FxHashSet::default(); + + if let Some((trait_migration_cause, diagnostics_info)) = self.compute_2229_migrations_for_trait(min_captures, var_hir_id, closure_clause) { need_migration = true; auto_trait_reasons.extend(trait_migration_cause); + responsible_captured_hir_ids.extend(diagnostics_info); } - if self.compute_2229_migrations_for_drop( + if let Some(diagnostics_info) = self.compute_2229_migrations_for_drop( closure_def_id, closure_span, min_captures, @@ -850,10 +879,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { need_migration = true; drop_reorder_reason = true; + responsible_captured_hir_ids.extend(diagnostics_info); } if need_migration { - need_migrations.push(var_hir_id); + need_migrations.push((var_hir_id, responsible_captured_hir_ids)); } } @@ -1877,10 +1907,10 @@ fn should_do_rust_2021_incompatible_closure_captures_analysis( /// - s2: Comma separated names of the variables being migrated. fn migration_suggestion_for_2229( tcx: TyCtxt<'_>, - need_migrations: &Vec, + need_migrations: &Vec<(hir::HirId, FxHashSet<(Option, String)>)>, ) -> (String, String) { let need_migrations_variables = - need_migrations.iter().map(|v| var_name(tcx, *v)).collect::>(); + need_migrations.iter().map(|(v, _)| var_name(tcx, *v)).collect::>(); let migration_ref_concat = need_migrations_variables.iter().map(|v| format!("&{}", v)).collect::>().join(", "); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr index 3d3dde15412bf..39b9dc2e22fa4 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr @@ -6,6 +6,7 @@ LL | thread::spawn(move || unsafe { LL | | LL | | LL | | *fptr.0 = 20; + | | ------- in Rust 2018, closure captures all of `fptr`, but in Rust 2021, it only captures `fptr.0` LL | | }); | |_____^ | @@ -32,6 +33,7 @@ LL | thread::spawn(move || unsafe { LL | | LL | | LL | | *fptr.0.0 = 20; + | | --------- in Rust 2018, closure captures all of `fptr`, but in Rust 2021, it only captures `fptr.0.0` LL | | }); | |_____^ | @@ -53,6 +55,7 @@ LL | let c = || { LL | | LL | | LL | | let f_1 = f.1; + | | --- in Rust 2018, closure captures all of `f`, but in Rust 2021, it only captures `f.1` LL | | println!("{:?}", f_1.0); LL | | }; | |_____^ 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 51d9c4881af3f..71fa99997d388 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 @@ -18,8 +18,11 @@ fn test1_all_need_migration() { //~| HELP: add a dummy let to cause `t`, `t1`, `t2` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` let _t1 = t1.0; + //~^ NOTE: in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.0` let _t2 = t2.0; + //~^ NOTE: in Rust 2018, closure captures all of `t2`, but in Rust 2021, it only captures `t2.0` }; c(); @@ -37,7 +40,9 @@ fn test2_only_precise_paths_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t`, `t1` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` let _t1 = t1.0; + //~^ NOTE: in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.0` let _t2 = t2; }; @@ -54,6 +59,7 @@ fn test3_only_by_value_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` println!("{}", t1.1); }; @@ -73,6 +79,7 @@ fn test4_only_non_copy_types_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` let _t1 = t1.0; }; @@ -92,6 +99,7 @@ fn test5_only_drop_types_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` let _s = s.0; }; @@ -108,6 +116,8 @@ fn test6_move_closures_non_copy_types_might_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t1`, `t` to be fully captured println!("{} {}", t1.1, t.1); + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.1` + //~| NOTE: in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.1` }; c(); @@ -124,6 +134,7 @@ fn test7_drop_non_drop_aggregate_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` }; c(); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs index c732cbb4fa51e..a80aa92aa80f4 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs @@ -18,8 +18,11 @@ fn test1_all_need_migration() { //~| HELP: add a dummy let to cause `t`, `t1`, `t2` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` let _t1 = t1.0; + //~^ NOTE: in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.0` let _t2 = t2.0; + //~^ NOTE: in Rust 2018, closure captures all of `t2`, but in Rust 2021, it only captures `t2.0` }; c(); @@ -37,7 +40,9 @@ fn test2_only_precise_paths_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t`, `t1` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` let _t1 = t1.0; + //~^ NOTE: in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.0` let _t2 = t2; }; @@ -54,6 +59,7 @@ fn test3_only_by_value_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` println!("{}", t1.1); }; @@ -73,6 +79,7 @@ fn test4_only_non_copy_types_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` let _t1 = t1.0; }; @@ -92,6 +99,7 @@ fn test5_only_drop_types_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` let _s = s.0; }; @@ -108,6 +116,8 @@ fn test6_move_closures_non_copy_types_might_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t1`, `t` to be fully captured println!("{} {}", t1.1, t.1); + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.1` + //~| NOTE: in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.1` }; c(); @@ -124,6 +134,7 @@ fn test7_drop_non_drop_aggregate_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `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 89a2b0eb95366..64708027383db 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 @@ -6,8 +6,16 @@ LL | let c = || { LL | | LL | | LL | | -... | +LL | | +LL | | let _t = t.0; + | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +LL | | +LL | | let _t1 = t1.0; + | | ---- in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.0` +LL | | LL | | let _t2 = t2.0; + | | ---- in Rust 2018, closure captures all of `t2`, but in Rust 2021, it only captures `t2.0` +LL | | LL | | }; | |_____^ | @@ -28,14 +36,19 @@ LL | let _t = t.0; ... error: drop order will change in Rust 2021 - --> $DIR/insignificant_drop.rs:35:13 + --> $DIR/insignificant_drop.rs:38:13 | LL | let c = || { | _____________^ LL | | LL | | LL | | -... | +LL | | let _t = t.0; + | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +LL | | +LL | | let _t1 = t1.0; + | | ---- in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.0` +LL | | LL | | let _t2 = t2; LL | | }; | |_____^ @@ -48,11 +61,11 @@ LL | LL | LL | LL | let _t = t.0; -LL | let _t1 = t1.0; +LL | ... error: drop order will change in Rust 2021 - --> $DIR/insignificant_drop.rs:52:13 + --> $DIR/insignificant_drop.rs:57:13 | LL | let c = || { | _____________^ @@ -60,6 +73,8 @@ LL | | LL | | LL | | LL | | let _t = t.0; + | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +LL | | LL | | println!("{}", t1.1); LL | | }; | |_____^ @@ -72,11 +87,11 @@ LL | LL | LL | LL | let _t = t.0; -LL | println!("{}", t1.1); +LL | ... error: drop order will change in Rust 2021 - --> $DIR/insignificant_drop.rs:71:13 + --> $DIR/insignificant_drop.rs:77:13 | LL | let c = || { | _____________^ @@ -84,6 +99,8 @@ LL | | LL | | LL | | LL | | let _t = t.0; + | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +LL | | LL | | let _t1 = t1.0; LL | | }; | |_____^ @@ -96,11 +113,11 @@ LL | LL | LL | LL | let _t = t.0; -LL | let _t1 = t1.0; +LL | ... error: drop order will change in Rust 2021 - --> $DIR/insignificant_drop.rs:90:13 + --> $DIR/insignificant_drop.rs:97:13 | LL | let c = || { | _____________^ @@ -108,6 +125,8 @@ LL | | LL | | LL | | LL | | let _t = t.0; + | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +LL | | LL | | let _s = s.0; LL | | }; | |_____^ @@ -120,11 +139,11 @@ LL | LL | LL | LL | let _t = t.0; -LL | let _s = s.0; +LL | ... error: drop order will change in Rust 2021 - --> $DIR/insignificant_drop.rs:106:13 + --> $DIR/insignificant_drop.rs:114:13 | LL | let c = move || { | _____________^ @@ -132,6 +151,11 @@ LL | | LL | | LL | | LL | | println!("{} {}", t1.1, t.1); + | | ---- --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.1` + | | | + | | in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.1` +LL | | +LL | | LL | | }; | |_____^ | @@ -143,11 +167,11 @@ LL | LL | LL | LL | println!("{} {}", t1.1, t.1); -LL | }; - | +LL | + ... error: drop order will change in Rust 2021 - --> $DIR/insignificant_drop.rs:122:13 + --> $DIR/insignificant_drop.rs:132:13 | LL | let c = || { | _____________^ @@ -155,6 +179,8 @@ LL | | LL | | LL | | LL | | let _t = t.0; + | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +LL | | LL | | }; | |_____^ | @@ -166,8 +192,8 @@ LL | 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/insignificant_drop_attr_migrations.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed index 8c85cd990d308..f150bd8cc9cbb 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed @@ -39,6 +39,7 @@ fn significant_drop_needs_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` }; c(); @@ -57,6 +58,7 @@ fn generic_struct_with_significant_drop_needs_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.1; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.1` }; c(); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs index 17cee28e31117..03c0ab959b25c 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs @@ -39,6 +39,7 @@ fn significant_drop_needs_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` }; c(); @@ -57,6 +58,7 @@ fn generic_struct_with_significant_drop_needs_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.1; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.1` }; c(); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr index 1d3bda03d0e16..478b331f7fa5b 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr @@ -7,6 +7,8 @@ LL | | LL | | LL | | LL | | let _t = t.0; + | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +LL | | LL | | }; | |_____^ | @@ -23,11 +25,11 @@ LL | LL | LL | LL | let _t = t.0; -LL | }; - | +LL | + ... error: drop order will change in Rust 2021 - --> $DIR/insignificant_drop_attr_migrations.rs:55:13 + --> $DIR/insignificant_drop_attr_migrations.rs:56:13 | LL | let c = move || { | _____________^ @@ -35,6 +37,8 @@ LL | | LL | | LL | | LL | | let _t = t.1; + | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.1` +LL | | LL | | }; | |_____^ | @@ -46,8 +50,8 @@ LL | LL | LL | LL | let _t = t.1; -LL | }; - | +LL | + ... error: aborting due to 2 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 index c974299c1536b..a4a38d47500df 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.fixed @@ -21,6 +21,8 @@ fn closure_contains_block() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` + }; c(); @@ -30,6 +32,7 @@ fn closure_doesnt_contain_block() { let t = (Foo(0), Foo(0)); let c = || { let _ = &t; t.0 }; //~^ ERROR: drop order + //~| NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured 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 index dd9556aa56784..01a47dffd85a8 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.rs @@ -21,6 +21,8 @@ fn closure_contains_block() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` + }; c(); @@ -30,6 +32,7 @@ fn closure_doesnt_contain_block() { let t = (Foo(0), Foo(0)); let c = || t.0; //~^ ERROR: drop order + //~| NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured 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 index 2d5e5e5e55c14..58109128c2c07 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr @@ -7,6 +7,9 @@ LL | | LL | | LL | | LL | | let _t = t.0; + | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +LL | | +LL | | LL | | }; | |_____^ | @@ -23,14 +26,16 @@ LL | LL | LL | LL | let _t = t.0; -LL | }; - | +LL | + ... error: drop order will change in Rust 2021 - --> $DIR/migrations_rustfix.rs:31:13 + --> $DIR/migrations_rustfix.rs:33:13 | LL | let c = || t.0; - | ^^^^^^ + | ^^^--- + | | + | in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` | = note: for more information, see help: add a dummy let to cause `t` to be fully captured diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr index dca5c454b83be..2513ceecc6998 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr @@ -6,6 +6,7 @@ LL | let result = panic::catch_unwind(move || { LL | | LL | | LL | | f.0() + | | --- in Rust 2018, closure captures all of `f`, but in Rust 2021, it only captures `f.0` LL | | }); | |_____^ | 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 2788207296f11..09829123db3f4 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/precise.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/precise.stderr @@ -6,6 +6,7 @@ LL | let c = || { LL | | LL | | LL | | let _t = t.0; + | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` LL | | let _t = &t.1; LL | | }; | |_____^ @@ -34,8 +35,11 @@ LL | let c = || { LL | | LL | | LL | | let _x = u.0.0; + | | ----- in Rust 2018, closure captures all of `u`, but in Rust 2021, it only captures `u.0.0` LL | | let _x = u.0.1; + | | ----- in Rust 2018, closure captures all of `u`, but in Rust 2021, it only captures `u.0.1` LL | | let _x = u.1.0; + | | ----- in Rust 2018, closure captures all of `u`, but in Rust 2021, it only captures `u.1.0` LL | | }; | |_____^ | 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 58ed2de26b3a7..5bdefb6762e4f 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 @@ -27,8 +27,11 @@ fn test1_all_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t`, `t1`, `t2` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` let _t1 = t1.0; + //~^ NOTE: in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.0` let _t2 = t2.0; + //~^ NOTE: in Rust 2018, closure captures all of `t2`, but in Rust 2021, it only captures `t2.0` }; c(); @@ -46,7 +49,9 @@ fn test2_only_precise_paths_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t`, `t1` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` let _t1 = t1.0; + //~^ NOTE: in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.0` let _t2 = t2; }; @@ -63,6 +68,7 @@ fn test3_only_by_value_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` println!("{:?}", t1.1); }; @@ -81,6 +87,7 @@ fn test4_type_contains_drop_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` }; c(); @@ -97,6 +104,7 @@ fn test5_drop_non_drop_aggregate_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` }; c(); @@ -111,6 +119,7 @@ fn test6_significant_insignificant_drop_aggregate_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.1; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.1` }; c(); @@ -127,6 +136,8 @@ fn test7_move_closures_non_copy_types_might_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t1`, `t` to be fully captured println!("{:?} {:?}", t1.1, t.1); + //~^ NOTE: in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.1` + //~| NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.1` }; c(); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs index 0890fc1c21256..44119a76e14d0 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs @@ -27,8 +27,11 @@ fn test1_all_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t`, `t1`, `t2` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` let _t1 = t1.0; + //~^ NOTE: in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.0` let _t2 = t2.0; + //~^ NOTE: in Rust 2018, closure captures all of `t2`, but in Rust 2021, it only captures `t2.0` }; c(); @@ -46,7 +49,9 @@ fn test2_only_precise_paths_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t`, `t1` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` let _t1 = t1.0; + //~^ NOTE: in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.0` let _t2 = t2; }; @@ -63,6 +68,7 @@ fn test3_only_by_value_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` println!("{:?}", t1.1); }; @@ -81,6 +87,7 @@ fn test4_type_contains_drop_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` }; c(); @@ -97,6 +104,7 @@ fn test5_drop_non_drop_aggregate_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` }; c(); @@ -111,6 +119,7 @@ fn test6_significant_insignificant_drop_aggregate_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.1; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.1` }; c(); @@ -127,6 +136,8 @@ fn test7_move_closures_non_copy_types_might_need_migration() { //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t1`, `t` to be fully captured println!("{:?} {:?}", t1.1, t.1); + //~^ NOTE: in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.1` + //~| NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `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 ebf9f169fd400..fa4903b76badf 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 @@ -6,8 +6,15 @@ LL | let c = || { LL | | LL | | LL | | -... | +LL | | let _t = t.0; + | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +LL | | +LL | | let _t1 = t1.0; + | | ---- in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.0` +LL | | LL | | let _t2 = t2.0; + | | ---- in Rust 2018, closure captures all of `t2`, but in Rust 2021, it only captures `t2.0` +LL | | LL | | }; | |_____^ | @@ -24,18 +31,23 @@ LL | LL | LL | LL | let _t = t.0; -LL | let _t1 = t1.0; +LL | ... error: drop order will change in Rust 2021 - --> $DIR/significant_drop.rs:44:13 + --> $DIR/significant_drop.rs:47:13 | LL | let c = || { | _____________^ LL | | LL | | LL | | -... | +LL | | let _t = t.0; + | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +LL | | +LL | | let _t1 = t1.0; + | | ---- in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.0` +LL | | LL | | let _t2 = t2; LL | | }; | |_____^ @@ -48,11 +60,11 @@ LL | LL | LL | LL | let _t = t.0; -LL | let _t1 = t1.0; +LL | ... error: drop order will change in Rust 2021 - --> $DIR/significant_drop.rs:61:13 + --> $DIR/significant_drop.rs:66:13 | LL | let c = || { | _____________^ @@ -60,6 +72,8 @@ LL | | LL | | LL | | LL | | let _t = t.0; + | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +LL | | LL | | println!("{:?}", t1.1); LL | | }; | |_____^ @@ -72,11 +86,11 @@ LL | LL | LL | LL | let _t = t.0; -LL | println!("{:?}", t1.1); +LL | ... error: drop order will change in Rust 2021 - --> $DIR/significant_drop.rs:79:13 + --> $DIR/significant_drop.rs:85:13 | LL | let c = || { | _____________^ @@ -84,6 +98,8 @@ LL | | LL | | LL | | LL | | let _t = t.0; + | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +LL | | LL | | }; | |_____^ | @@ -95,11 +111,11 @@ LL | LL | LL | LL | let _t = t.0; -LL | }; - | +LL | + ... error: drop order will change in Rust 2021 - --> $DIR/significant_drop.rs:95:13 + --> $DIR/significant_drop.rs:102:13 | LL | let c = || { | _____________^ @@ -107,6 +123,8 @@ LL | | LL | | LL | | LL | | let _t = t.0; + | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +LL | | LL | | }; | |_____^ | @@ -118,11 +136,11 @@ LL | LL | LL | LL | let _t = t.0; -LL | }; - | +LL | + ... error: drop order will change in Rust 2021 - --> $DIR/significant_drop.rs:109:13 + --> $DIR/significant_drop.rs:117:13 | LL | let c = || { | _____________^ @@ -130,6 +148,8 @@ LL | | LL | | LL | | LL | | let _t = t.1; + | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.1` +LL | | LL | | }; | |_____^ | @@ -141,11 +161,11 @@ LL | LL | LL | LL | let _t = t.1; -LL | }; - | +LL | + ... error: drop order will change in Rust 2021 - --> $DIR/significant_drop.rs:125:13 + --> $DIR/significant_drop.rs:134:13 | LL | let c = move || { | _____________^ @@ -153,6 +173,11 @@ LL | | LL | | LL | | LL | | println!("{:?} {:?}", t1.1, t.1); + | | ---- --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.1` + | | | + | | in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.1` +LL | | +LL | | LL | | }; | |_____^ | @@ -164,8 +189,8 @@ LL | LL | LL | LL | println!("{:?} {:?}", t1.1, t.1); -LL | }; - | +LL | + ... error: aborting due to 7 previous errors From 0e8e89daa6c53b32e866205fd00ba385c66b90de Mon Sep 17 00:00:00 2001 From: Roxane Date: Tue, 6 Jul 2021 16:49:07 -0400 Subject: [PATCH 2/9] Update error message --- compiler/rustc_typeck/src/check/upvar.rs | 4 ++-- .../migrations/auto_traits.fixed | 6 +++--- .../migrations/auto_traits.rs | 6 +++--- .../migrations/auto_traits.stderr | 6 +++--- .../migrations/insignificant_drop.stderr | 14 +++++++------- .../insignificant_drop_attr_migrations.stderr | 4 ++-- .../migrations/migrations_rustfix.stderr | 4 ++-- .../migrations/mir_calls_to_shims.fixed | 2 +- .../migrations/mir_calls_to_shims.rs | 2 +- .../migrations/mir_calls_to_shims.stderr | 2 +- .../migrations/precise.stderr | 4 ++-- .../migrations/significant_drop.stderr | 14 +++++++------- 12 files changed, 34 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 106fea2b2f73d..3f042dbd4a56a 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -505,7 +505,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |lint| { let mut diagnostics_builder = lint.build( format!( - "{} will change in Rust 2021", + "changes to closure capture in Rust 2021 will affect {}", reasons ) .as_str(), @@ -567,7 +567,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if auto_trait_reasons.len() > 0 { reasons = format!( - "{} trait implementation", + "{} closure trait implementation", auto_trait_reasons.clone().into_iter().collect::>().join(", ") ); } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed index 134d07c400b3a..7c7387ff14ee8 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed @@ -11,7 +11,7 @@ fn test_send_trait() { let mut f = 10; let fptr = SendPointer(&mut f as *mut i32); thread::spawn(move || { let _ = &fptr; unsafe { - //~^ ERROR: `Send` trait implementation + //~^ ERROR: `Send` closure trait implementation //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0 = 20; } }); @@ -28,7 +28,7 @@ fn test_sync_trait() { let f = CustomInt(&mut f as *mut i32); let fptr = SyncPointer(f); thread::spawn(move || { let _ = &fptr; unsafe { - //~^ ERROR: `Sync`, `Send` trait implementation + //~^ ERROR: `Sync`, `Send` closure trait implementation //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0.0 = 20; } }); @@ -49,7 +49,7 @@ impl Clone for U { fn test_clone_trait() { let f = U(S(String::from("Hello World")), T(0)); let c = || { let _ = &f; - //~^ ERROR: `Clone` trait implementation, and drop order + //~^ ERROR: `Clone` closure trait implementation, and drop order //~| HELP: add a dummy let to cause `f` to be fully captured let f_1 = f.1; println!("{:?}", f_1.0); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs index b48a724f052f0..e606a206b3b78 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs @@ -11,7 +11,7 @@ fn test_send_trait() { let mut f = 10; let fptr = SendPointer(&mut f as *mut i32); thread::spawn(move || unsafe { - //~^ ERROR: `Send` trait implementation + //~^ ERROR: `Send` closure trait implementation //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0 = 20; }); @@ -28,7 +28,7 @@ fn test_sync_trait() { let f = CustomInt(&mut f as *mut i32); let fptr = SyncPointer(f); thread::spawn(move || unsafe { - //~^ ERROR: `Sync`, `Send` trait implementation + //~^ ERROR: `Sync`, `Send` closure trait implementation //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0.0 = 20; }); @@ -49,7 +49,7 @@ impl Clone for U { fn test_clone_trait() { let f = U(S(String::from("Hello World")), T(0)); let c = || { - //~^ ERROR: `Clone` trait implementation, and drop order + //~^ ERROR: `Clone` closure trait implementation, and drop order //~| HELP: add a dummy let to cause `f` to be fully captured let f_1 = f.1; println!("{:?}", f_1.0); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr index 39b9dc2e22fa4..b628c5c3fad9f 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr @@ -1,4 +1,4 @@ -error: `Send` trait implementation will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect `Send` closure trait implementation --> $DIR/auto_traits.rs:13:19 | LL | thread::spawn(move || unsafe { @@ -25,7 +25,7 @@ LL | *fptr.0 = 20; LL | } }); | -error: `Sync`, `Send` trait implementation will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` closure trait implementation --> $DIR/auto_traits.rs:30:19 | LL | thread::spawn(move || unsafe { @@ -47,7 +47,7 @@ LL | *fptr.0.0 = 20; LL | } }); | -error: `Clone` trait implementation, and drop order will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect `Clone` closure trait implementation, and drop order --> $DIR/auto_traits.rs:51:13 | LL | let 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 64708027383db..11b90a700551a 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 @@ -1,4 +1,4 @@ -error: drop order will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/insignificant_drop.rs:15:13 | LL | let c = || { @@ -35,7 +35,7 @@ LL | LL | let _t = t.0; ... -error: drop order will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/insignificant_drop.rs:38:13 | LL | let c = || { @@ -64,7 +64,7 @@ LL | let _t = t.0; LL | ... -error: drop order will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/insignificant_drop.rs:57:13 | LL | let c = || { @@ -90,7 +90,7 @@ LL | let _t = t.0; LL | ... -error: drop order will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/insignificant_drop.rs:77:13 | LL | let c = || { @@ -116,7 +116,7 @@ LL | let _t = t.0; LL | ... -error: drop order will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/insignificant_drop.rs:97:13 | LL | let c = || { @@ -142,7 +142,7 @@ LL | let _t = t.0; LL | ... -error: drop order will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/insignificant_drop.rs:114:13 | LL | let c = move || { @@ -170,7 +170,7 @@ LL | println!("{} {}", t1.1, t.1); LL | ... -error: drop order will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/insignificant_drop.rs:132:13 | LL | let c = || { diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr index 478b331f7fa5b..b328abfeb52af 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr @@ -1,4 +1,4 @@ -error: drop order will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/insignificant_drop_attr_migrations.rs:37:13 | LL | let c = || { @@ -28,7 +28,7 @@ LL | let _t = t.0; LL | ... -error: drop order will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/insignificant_drop_attr_migrations.rs:56:13 | LL | let c = move || { 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 index 58109128c2c07..a4426c79a166c 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr @@ -1,4 +1,4 @@ -error: drop order will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/migrations_rustfix.rs:19:13 | LL | let c = || { @@ -29,7 +29,7 @@ LL | let _t = t.0; LL | ... -error: drop order will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/migrations_rustfix.rs:33:13 | LL | let c = || t.0; diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed index 7f49b460ef63a..309a3c4a70bfb 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed @@ -17,7 +17,7 @@ where { let f = panic::AssertUnwindSafe(f); let result = panic::catch_unwind(move || { let _ = &f; - //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` trait implementation + //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` closure trait implementation //~| HELP: add a dummy let to cause `f` to be fully captured f.0() }); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs index 3c654bec52605..690e509b318b4 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs @@ -17,7 +17,7 @@ where { let f = panic::AssertUnwindSafe(f); let result = panic::catch_unwind(move || { - //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` trait implementation + //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` closure trait implementation //~| HELP: add a dummy let to cause `f` to be fully captured f.0() }); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr index 2513ceecc6998..3925a0fdb980e 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr @@ -1,4 +1,4 @@ -error: `UnwindSafe`, `RefUnwindSafe` trait implementation will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect `UnwindSafe`, `RefUnwindSafe` closure trait implementation --> $DIR/mir_calls_to_shims.rs:19:38 | LL | let result = panic::catch_unwind(move || { 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 09829123db3f4..00ee8b1f0543f 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/precise.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/precise.stderr @@ -1,4 +1,4 @@ -error: drop order will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/precise.rs:19:13 | LL | let c = || { @@ -27,7 +27,7 @@ LL | let _t = &t.1; LL | }; | -error: drop order will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/precise.rs:41:13 | LL | let 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 fa4903b76badf..f715ea9a48f7d 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 @@ -1,4 +1,4 @@ -error: drop order will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/significant_drop.rs:25:13 | LL | let c = || { @@ -34,7 +34,7 @@ LL | let _t = t.0; LL | ... -error: drop order will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/significant_drop.rs:47:13 | LL | let c = || { @@ -63,7 +63,7 @@ LL | let _t = t.0; LL | ... -error: drop order will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/significant_drop.rs:66:13 | LL | let c = || { @@ -89,7 +89,7 @@ LL | let _t = t.0; LL | ... -error: drop order will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/significant_drop.rs:85:13 | LL | let c = || { @@ -114,7 +114,7 @@ LL | let _t = t.0; LL | ... -error: drop order will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/significant_drop.rs:102:13 | LL | let c = || { @@ -139,7 +139,7 @@ LL | let _t = t.0; LL | ... -error: drop order will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/significant_drop.rs:117:13 | LL | let c = || { @@ -164,7 +164,7 @@ LL | let _t = t.1; LL | ... -error: drop order will change in Rust 2021 +error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/significant_drop.rs:134:13 | LL | let c = move || { From 2900c1a5e82b9c43917ba4e3e4ca347289b3d21a Mon Sep 17 00:00:00 2001 From: Roxane Date: Wed, 7 Jul 2021 10:29:06 -0400 Subject: [PATCH 3/9] Add note pointing to where a closure and it's captured variables are dropped --- compiler/rustc_typeck/src/check/upvar.rs | 40 +++++++ .../migrations/auto_traits.fixed | 8 ++ .../migrations/auto_traits.rs | 8 ++ .../migrations/auto_traits.stderr | 31 ++++-- .../migrations/insignificant_drop.fixed | 11 ++ .../migrations/insignificant_drop.rs | 11 ++ .../migrations/insignificant_drop.stderr | 43 ++++++-- .../insignificant_drop_attr_migrations.fixed | 2 + .../insignificant_drop_attr_migrations.rs | 2 + .../insignificant_drop_attr_migrations.stderr | 8 +- .../migrations/migrations_rustfix.fixed | 3 +- .../migrations/migrations_rustfix.rs | 3 +- .../migrations/migrations_rustfix.stderr | 7 +- .../migrations/mir_calls_to_shims.fixed | 3 + .../migrations/mir_calls_to_shims.rs | 3 + .../migrations/mir_calls_to_shims.stderr | 9 +- .../migrations/precise.stderr | 6 ++ .../migrations/significant_drop.fixed | 52 +++++++++ .../migrations/significant_drop.rs | 52 +++++++++ .../migrations/significant_drop.stderr | 101 ++++++++++++++++-- 20 files changed, 373 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 3f042dbd4a56a..a5c4e161771a1 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -511,6 +511,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .as_str(), ); for (var_hir_id, diagnostics_info) in need_migrations.iter() { + let mut captured_names = format!(""); for (captured_hir_id, captured_name) in diagnostics_info.iter() { if let Some(captured_hir_id) = captured_hir_id { let cause_span = self.tcx.hir().span(*captured_hir_id); @@ -518,8 +519,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.hir().name(*var_hir_id), captured_name, )); + if captured_names == "" { + captured_names = format!("`{}`", captured_name); + } else { + captured_names = format!("{}, `{}`", captured_names, captured_name); + } } } + + if reasons.contains("drop order") { + let drop_location_span = drop_location_span(self.tcx, &closure_hir_id); + + diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` would be dropped here, but in Rust 2021, only {} would be dropped here alongside the closure", + self.tcx.hir().name(*var_hir_id), + captured_names, + )); + } } diagnostics_builder.note("for more information, see "); let closure_body_span = self.tcx.hir().span(body_id.hir_id); @@ -1350,6 +1365,31 @@ fn apply_capture_kind_on_capture_ty( } } +/// Returns the Span of where the value with the provided HirId would be dropped +fn drop_location_span(tcx: TyCtxt<'tcx>, hir_id: &hir::HirId) -> Span { + let owner_id = tcx.hir().get_enclosing_scope(*hir_id).unwrap(); + + let owner_node = tcx.hir().get(owner_id); + match owner_node { + hir::Node::Item(item) => match item.kind { + hir::ItemKind::Fn(_, _, owner_id) => { + let owner_span = tcx.hir().span(owner_id.hir_id); + tcx.sess.source_map().end_point(owner_span) + } + _ => { + bug!("Drop location span error: need to handle more ItemKind {:?}", item.kind); + } + }, + hir::Node::Block(block) => { + let owner_span = tcx.hir().span(block.hir_id); + tcx.sess.source_map().end_point(owner_span) + } + _ => { + bug!("Drop location span error: need to handle more Node {:?}", owner_node); + } + } +} + struct InferBorrowKind<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed index 7c7387ff14ee8..ca55152cc2a83 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed @@ -1,5 +1,6 @@ // run-rustfix #![deny(rust_2021_incompatible_closure_captures)] +//~^ NOTE: the lint level is defined here use std::thread; @@ -12,8 +13,10 @@ fn test_send_trait() { let fptr = SendPointer(&mut f as *mut i32); thread::spawn(move || { let _ = &fptr; unsafe { //~^ ERROR: `Send` closure trait implementation + //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0 = 20; + //~^ NOTE: in Rust 2018, closure captures all of `fptr`, but in Rust 2021, it only captures `fptr.0` } }); } @@ -29,8 +32,10 @@ fn test_sync_trait() { let fptr = SyncPointer(f); thread::spawn(move || { let _ = &fptr; unsafe { //~^ ERROR: `Sync`, `Send` closure trait implementation + //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0.0 = 20; + //~^ NOTE: in Rust 2018, closure captures all of `fptr`, but in Rust 2021, it only captures `fptr.0.0` } }); } @@ -50,8 +55,10 @@ fn test_clone_trait() { let f = U(S(String::from("Hello World")), T(0)); let c = || { let _ = &f; //~^ ERROR: `Clone` closure trait implementation, and drop order + //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured let f_1 = f.1; + //~^ NOTE: in Rust 2018, closure captures all of `f`, but in Rust 2021, it only captures `f.1` println!("{:?}", f_1.0); }; @@ -59,6 +66,7 @@ fn test_clone_trait() { c_clone(); } +//~^ NOTE: in Rust 2018, `f` would be dropped here, but in Rust 2021, only `f.1` would be dropped here alongside the closure fn main() { test_send_trait(); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs index e606a206b3b78..66c43cd865be2 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs @@ -1,5 +1,6 @@ // run-rustfix #![deny(rust_2021_incompatible_closure_captures)] +//~^ NOTE: the lint level is defined here use std::thread; @@ -12,8 +13,10 @@ fn test_send_trait() { let fptr = SendPointer(&mut f as *mut i32); thread::spawn(move || unsafe { //~^ ERROR: `Send` closure trait implementation + //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0 = 20; + //~^ NOTE: in Rust 2018, closure captures all of `fptr`, but in Rust 2021, it only captures `fptr.0` }); } @@ -29,8 +32,10 @@ fn test_sync_trait() { let fptr = SyncPointer(f); thread::spawn(move || unsafe { //~^ ERROR: `Sync`, `Send` closure trait implementation + //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0.0 = 20; + //~^ NOTE: in Rust 2018, closure captures all of `fptr`, but in Rust 2021, it only captures `fptr.0.0` }); } @@ -50,8 +55,10 @@ fn test_clone_trait() { let f = U(S(String::from("Hello World")), T(0)); let c = || { //~^ ERROR: `Clone` closure trait implementation, and drop order + //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured let f_1 = f.1; + //~^ NOTE: in Rust 2018, closure captures all of `f`, but in Rust 2021, it only captures `f.1` println!("{:?}", f_1.0); }; @@ -59,6 +66,7 @@ fn test_clone_trait() { c_clone(); } +//~^ NOTE: in Rust 2018, `f` would be dropped here, but in Rust 2021, only `f.1` would be dropped here alongside the closure fn main() { test_send_trait(); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr index b628c5c3fad9f..38f8976058d3d 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr @@ -1,12 +1,14 @@ error: changes to closure capture in Rust 2021 will affect `Send` closure trait implementation - --> $DIR/auto_traits.rs:13:19 + --> $DIR/auto_traits.rs:14:19 | LL | thread::spawn(move || unsafe { | ___________________^ LL | | LL | | +LL | | LL | | *fptr.0 = 20; | | ------- in Rust 2018, closure captures all of `fptr`, but in Rust 2021, it only captures `fptr.0` +LL | | LL | | }); | |_____^ | @@ -21,19 +23,22 @@ help: add a dummy let to cause `fptr` to be fully captured LL | thread::spawn(move || { let _ = &fptr; unsafe { LL | LL | +LL | LL | *fptr.0 = 20; -LL | } }); - | +LL | + ... error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` closure trait implementation - --> $DIR/auto_traits.rs:30:19 + --> $DIR/auto_traits.rs:33:19 | LL | thread::spawn(move || unsafe { | ___________________^ LL | | LL | | +LL | | LL | | *fptr.0.0 = 20; | | --------- in Rust 2018, closure captures all of `fptr`, but in Rust 2021, it only captures `fptr.0.0` +LL | | LL | | }); | |_____^ | @@ -43,22 +48,28 @@ help: add a dummy let to cause `fptr` to be fully captured LL | thread::spawn(move || { let _ = &fptr; unsafe { LL | LL | +LL | LL | *fptr.0.0 = 20; -LL | } }); - | +LL | + ... error: changes to closure capture in Rust 2021 will affect `Clone` closure trait implementation, and drop order - --> $DIR/auto_traits.rs:51:13 + --> $DIR/auto_traits.rs:56:13 | LL | let c = || { | _____________^ LL | | LL | | +LL | | LL | | let f_1 = f.1; | | --- in Rust 2018, closure captures all of `f`, but in Rust 2021, it only captures `f.1` +LL | | LL | | println!("{:?}", f_1.0); LL | | }; | |_____^ +... +LL | } + | - in Rust 2018, `f` would be dropped here, but in Rust 2021, only `f.1` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `f` to be fully captured @@ -66,10 +77,10 @@ help: add a dummy let to cause `f` to be fully captured LL | let c = || { let _ = &f; LL | LL | +LL | LL | let f_1 = f.1; -LL | println!("{:?}", f_1.0); -LL | }; - | +LL | + ... error: aborting due to 3 previous errors 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 71fa99997d388..e836f27cd7af1 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 @@ -27,6 +27,9 @@ fn test1_all_need_migration() { c(); } +//~^ in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure +//~| in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.0` would be dropped here alongside the closure +//~| in Rust 2018, `t2` would be dropped here, but in Rust 2021, only `t2.0` would be dropped here alongside the closure // String implements drop and therefore should be migrated. // But in this test cases, `t2` is completely captured and when it is dropped won't be affected @@ -48,6 +51,8 @@ fn test2_only_precise_paths_need_migration() { c(); } +//~^ in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure +//~| in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.0` would be dropped here alongside the closure // If a variable would've not been captured by value then it would've not been // dropped with the closure and therefore doesn't need migration. @@ -65,6 +70,7 @@ fn test3_only_by_value_need_migration() { c(); } +//~^ in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure // Copy types get copied into the closure instead of move. Therefore we don't need to // migrate then as their drop order isn't tied to the closure. @@ -85,6 +91,7 @@ fn test4_only_non_copy_types_need_migration() { c(); } +//~^ in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure fn test5_only_drop_types_need_migration() { struct S(i32, i32); @@ -105,6 +112,7 @@ fn test5_only_drop_types_need_migration() { c(); } +//~^ in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure // Since we are using a move closure here, both `t` and `t1` get moved // even though they are being used by ref inside the closure. @@ -122,6 +130,8 @@ fn test6_move_closures_non_copy_types_might_need_migration() { c(); } +//~^ in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.1` would be dropped here alongside the closure +//~| in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.1` would be dropped here alongside the closure // Test migration analysis in case of Drop + Non Drop aggregates. // Note we need migration here only because the non-copy (because Drop type) is captured, @@ -139,6 +149,7 @@ fn test7_drop_non_drop_aggregate_need_migration() { c(); } +//~^ in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure fn main() { test1_all_need_migration(); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs index a80aa92aa80f4..fbf9b983f07a2 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs @@ -27,6 +27,9 @@ fn test1_all_need_migration() { c(); } +//~^ in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure +//~| in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.0` would be dropped here alongside the closure +//~| in Rust 2018, `t2` would be dropped here, but in Rust 2021, only `t2.0` would be dropped here alongside the closure // String implements drop and therefore should be migrated. // But in this test cases, `t2` is completely captured and when it is dropped won't be affected @@ -48,6 +51,8 @@ fn test2_only_precise_paths_need_migration() { c(); } +//~^ in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure +//~| in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.0` would be dropped here alongside the closure // If a variable would've not been captured by value then it would've not been // dropped with the closure and therefore doesn't need migration. @@ -65,6 +70,7 @@ fn test3_only_by_value_need_migration() { c(); } +//~^ in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure // Copy types get copied into the closure instead of move. Therefore we don't need to // migrate then as their drop order isn't tied to the closure. @@ -85,6 +91,7 @@ fn test4_only_non_copy_types_need_migration() { c(); } +//~^ in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure fn test5_only_drop_types_need_migration() { struct S(i32, i32); @@ -105,6 +112,7 @@ fn test5_only_drop_types_need_migration() { c(); } +//~^ in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure // Since we are using a move closure here, both `t` and `t1` get moved // even though they are being used by ref inside the closure. @@ -122,6 +130,8 @@ fn test6_move_closures_non_copy_types_might_need_migration() { c(); } +//~^ in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.1` would be dropped here alongside the closure +//~| in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.1` would be dropped here alongside the closure // Test migration analysis in case of Drop + Non Drop aggregates. // Note we need migration here only because the non-copy (because Drop type) is captured, @@ -139,6 +149,7 @@ fn test7_drop_non_drop_aggregate_need_migration() { c(); } +//~^ in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure fn main() { test1_all_need_migration(); 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 11b90a700551a..e7b2cd1c55347 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,6 +18,13 @@ LL | | let _t2 = t2.0; LL | | LL | | }; | |_____^ +... +LL | } + | - + | | + | in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure + | in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.0` would be dropped here alongside the closure + | in Rust 2018, `t2` would be dropped here, but in Rust 2021, only `t2.0` would be dropped here alongside the closure | note: the lint level is defined here --> $DIR/insignificant_drop.rs:3:9 @@ -36,7 +43,7 @@ LL | let _t = t.0; ... error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop.rs:38:13 + --> $DIR/insignificant_drop.rs:41:13 | LL | let c = || { | _____________^ @@ -52,6 +59,12 @@ LL | | LL | | let _t2 = t2; LL | | }; | |_____^ +... +LL | } + | - + | | + | in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure + | in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t`, `t1` to be fully captured @@ -65,7 +78,7 @@ LL | ... error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop.rs:57:13 + --> $DIR/insignificant_drop.rs:62:13 | LL | let c = || { | _____________^ @@ -78,6 +91,9 @@ LL | | LL | | println!("{}", t1.1); LL | | }; | |_____^ +... +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -91,7 +107,7 @@ LL | ... error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop.rs:77:13 + --> $DIR/insignificant_drop.rs:83:13 | LL | let c = || { | _____________^ @@ -104,6 +120,9 @@ LL | | LL | | let _t1 = t1.0; LL | | }; | |_____^ +... +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -117,7 +136,7 @@ LL | ... error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop.rs:97:13 + --> $DIR/insignificant_drop.rs:104:13 | LL | let c = || { | _____________^ @@ -130,6 +149,9 @@ LL | | LL | | let _s = s.0; LL | | }; | |_____^ +... +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -143,7 +165,7 @@ LL | ... error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop.rs:114:13 + --> $DIR/insignificant_drop.rs:122:13 | LL | let c = move || { | _____________^ @@ -158,6 +180,12 @@ LL | | LL | | LL | | }; | |_____^ +... +LL | } + | - + | | + | in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.1` would be dropped here alongside the closure + | in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.1` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t1`, `t` to be fully captured @@ -171,7 +199,7 @@ LL | ... error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop.rs:132:13 + --> $DIR/insignificant_drop.rs:142:13 | LL | let c = || { | _____________^ @@ -183,6 +211,9 @@ LL | | let _t = t.0; LL | | LL | | }; | |_____^ +... +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t` to be fully captured diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed index f150bd8cc9cbb..4626c04e9ba6e 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed @@ -44,6 +44,7 @@ fn significant_drop_needs_migration() { c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure // Even if a type implements an insignificant drop, if it's // elements have a significant drop then the overall type is @@ -63,6 +64,7 @@ fn generic_struct_with_significant_drop_needs_migration() { c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.1` would be dropped here alongside the closure fn main() { significant_drop_needs_migration(); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs index 03c0ab959b25c..ebcf1551bacf6 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs @@ -44,6 +44,7 @@ fn significant_drop_needs_migration() { c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure // Even if a type implements an insignificant drop, if it's // elements have a significant drop then the overall type is @@ -63,6 +64,7 @@ fn generic_struct_with_significant_drop_needs_migration() { c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.1` would be dropped here alongside the closure fn main() { significant_drop_needs_migration(); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr index b328abfeb52af..97ff0409d0a63 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr @@ -11,6 +11,9 @@ LL | | let _t = t.0; LL | | LL | | }; | |_____^ +... +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure | note: the lint level is defined here --> $DIR/insignificant_drop_attr_migrations.rs:3:9 @@ -29,7 +32,7 @@ LL | ... error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop_attr_migrations.rs:56:13 + --> $DIR/insignificant_drop_attr_migrations.rs:57:13 | LL | let c = move || { | _____________^ @@ -41,6 +44,9 @@ LL | | let _t = t.1; LL | | LL | | }; | |_____^ +... +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.1` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t` to be fully captured 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 index a4a38d47500df..f3c15a2e6b676 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.fixed @@ -22,11 +22,11 @@ fn closure_contains_block() { //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` - }; c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure fn closure_doesnt_contain_block() { let t = (Foo(0), Foo(0)); @@ -38,6 +38,7 @@ fn closure_doesnt_contain_block() { c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure fn main() { closure_contains_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 index 01a47dffd85a8..50936d15302b7 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.rs @@ -22,11 +22,11 @@ fn closure_contains_block() { //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` - }; c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure fn closure_doesnt_contain_block() { let t = (Foo(0), Foo(0)); @@ -38,6 +38,7 @@ fn closure_doesnt_contain_block() { c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure fn main() { closure_contains_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 index a4426c79a166c..09bae6d3f1344 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr @@ -9,9 +9,11 @@ LL | | LL | | let _t = t.0; | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` LL | | -LL | | LL | | }; | |_____^ +... +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure | note: the lint level is defined here --> $DIR/migrations_rustfix.rs:2:9 @@ -36,6 +38,9 @@ LL | let c = || t.0; | ^^^--- | | | in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +... +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t` to be fully captured diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed index 309a3c4a70bfb..cb3148214b4b8 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed @@ -1,6 +1,7 @@ // run-rustfix #![deny(rust_2021_incompatible_closure_captures)] +//~^ NOTE: the lint level is defined here // ignore-wasm32-bare compiled with panic=abort by default #![feature(fn_traits)] #![feature(never_type)] @@ -18,8 +19,10 @@ where let f = panic::AssertUnwindSafe(f); let result = panic::catch_unwind(move || { let _ = &f; //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` closure trait implementation + //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured f.0() + //~^ NOTE: in Rust 2018, closure captures all of `f`, but in Rust 2021, it only captures `f.0` }); if let Ok(..) = result { panic!("diverging function returned"); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs index 690e509b318b4..f6f8ad2c52078 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs @@ -1,6 +1,7 @@ // run-rustfix #![deny(rust_2021_incompatible_closure_captures)] +//~^ NOTE: the lint level is defined here // ignore-wasm32-bare compiled with panic=abort by default #![feature(fn_traits)] #![feature(never_type)] @@ -18,8 +19,10 @@ where let f = panic::AssertUnwindSafe(f); let result = panic::catch_unwind(move || { //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` closure trait implementation + //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured f.0() + //~^ NOTE: in Rust 2018, closure captures all of `f`, but in Rust 2021, it only captures `f.0` }); if let Ok(..) = result { panic!("diverging function returned"); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr index 3925a0fdb980e..9a45e276fcdfc 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr @@ -1,12 +1,14 @@ error: changes to closure capture in Rust 2021 will affect `UnwindSafe`, `RefUnwindSafe` closure trait implementation - --> $DIR/mir_calls_to_shims.rs:19:38 + --> $DIR/mir_calls_to_shims.rs:20:38 | LL | let result = panic::catch_unwind(move || { | ______________________________________^ LL | | LL | | +LL | | LL | | f.0() | | --- in Rust 2018, closure captures all of `f`, but in Rust 2021, it only captures `f.0` +LL | | LL | | }); | |_____^ | @@ -21,9 +23,10 @@ help: add a dummy let to cause `f` to be fully captured LL | let result = panic::catch_unwind(move || { let _ = &f; LL | LL | +LL | LL | f.0() -LL | }); - | +LL | + ... error: aborting due to previous error 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 00ee8b1f0543f..7bec8ef06fce3 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/precise.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/precise.stderr @@ -10,6 +10,9 @@ LL | | let _t = t.0; LL | | let _t = &t.1; LL | | }; | |_____^ +... +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure | note: the lint level is defined here --> $DIR/precise.rs:3:9 @@ -42,6 +45,9 @@ LL | | let _x = u.1.0; | | ----- in Rust 2018, closure captures all of `u`, but in Rust 2021, it only captures `u.1.0` LL | | }; | |_____^ +... +LL | } + | - in Rust 2018, `u` would be dropped here, but in Rust 2021, only `u.0.1`, `u.0.0`, `u.1.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `u` to be fully captured 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 5bdefb6762e4f..236fdb9e26ea2 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 @@ -36,6 +36,9 @@ fn test1_all_need_migration() { c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure +//~| NOTE: in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.0` would be dropped here alongside the closure +//~| NOTE: in Rust 2018, `t2` would be dropped here, but in Rust 2021, only `t2.0` would be dropped here alongside the closure // String implements drop and therefore should be migrated. // But in this test cases, `t2` is completely captured and when it is dropped won't be affected @@ -57,6 +60,8 @@ fn test2_only_precise_paths_need_migration() { c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure +//~| NOTE: in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.0` would be dropped here alongside the closure // If a variable would've not been captured by value then it would've not been // dropped with the closure and therefore doesn't need migration. @@ -74,6 +79,7 @@ fn test3_only_by_value_need_migration() { c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure // The root variable might not implement drop themselves but some path starting // at the root variable might implement Drop. @@ -92,6 +98,7 @@ fn test4_type_contains_drop_need_migration() { c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure // Test migration analysis in case of Drop + Non Drop aggregates. // Note we need migration here only because the non-copy (because Drop type) is captured, @@ -109,6 +116,7 @@ fn test5_drop_non_drop_aggregate_need_migration() { c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure // Test migration analysis in case of Significant and Insignificant Drop aggregates. fn test6_significant_insignificant_drop_aggregate_need_migration() { @@ -124,6 +132,7 @@ fn test6_significant_insignificant_drop_aggregate_need_migration() { c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.1` would be dropped here alongside the closure // Since we are using a move closure here, both `t` and `t1` get moved // even though they are being used by ref inside the closure. @@ -142,6 +151,47 @@ fn test7_move_closures_non_copy_types_might_need_migration() { c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.1` would be dropped here alongside the closure +//~| NOTE: in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.1` would be dropped here alongside the closure + + +fn test8_drop_order_and_blocks() { + { + let tuple = + (String::from("foo"), String::from("bar")); + { + let c = || { let _ = &tuple; + //~^ ERROR: drop order + //~| NOTE: for more information, see + //~| HELP: add a dummy let to cause `tuple` to be fully captured + tuple.0; + //~^ NOTE: in Rust 2018, closure captures all of `tuple`, but in Rust 2021, it only captures `tuple.0` + }; + + c(); + } + //~^ NOTE: in Rust 2018, `tuple` would be dropped here, but in Rust 2021, only `tuple.0` would be dropped here alongside the closure + } +} + +fn test9_drop_order_and_nested_closures() { + let tuple = + (String::from("foo"), String::from("bar")); + let b = || { + let c = || { let _ = &tuple; + //~^ ERROR: drop order + //~| NOTE: for more information, see + //~| HELP: add a dummy let to cause `tuple` to be fully captured + tuple.0; + //~^ NOTE: in Rust 2018, closure captures all of `tuple`, but in Rust 2021, it only captures `tuple.0` + }; + + c(); + }; + //~^ NOTE: in Rust 2018, `tuple` would be dropped here, but in Rust 2021, only `tuple.0` would be dropped here alongside the closure + + b(); +} fn main() { test1_all_need_migration(); @@ -151,4 +201,6 @@ fn main() { test5_drop_non_drop_aggregate_need_migration(); test6_significant_insignificant_drop_aggregate_need_migration(); test7_move_closures_non_copy_types_might_need_migration(); + test8_drop_order_and_blocks(); + test9_drop_order_and_nested_closures(); } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs index 44119a76e14d0..a57f7aa565e12 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs @@ -36,6 +36,9 @@ fn test1_all_need_migration() { c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure +//~| NOTE: in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.0` would be dropped here alongside the closure +//~| NOTE: in Rust 2018, `t2` would be dropped here, but in Rust 2021, only `t2.0` would be dropped here alongside the closure // String implements drop and therefore should be migrated. // But in this test cases, `t2` is completely captured and when it is dropped won't be affected @@ -57,6 +60,8 @@ fn test2_only_precise_paths_need_migration() { c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure +//~| NOTE: in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.0` would be dropped here alongside the closure // If a variable would've not been captured by value then it would've not been // dropped with the closure and therefore doesn't need migration. @@ -74,6 +79,7 @@ fn test3_only_by_value_need_migration() { c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure // The root variable might not implement drop themselves but some path starting // at the root variable might implement Drop. @@ -92,6 +98,7 @@ fn test4_type_contains_drop_need_migration() { c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure // Test migration analysis in case of Drop + Non Drop aggregates. // Note we need migration here only because the non-copy (because Drop type) is captured, @@ -109,6 +116,7 @@ fn test5_drop_non_drop_aggregate_need_migration() { c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure // Test migration analysis in case of Significant and Insignificant Drop aggregates. fn test6_significant_insignificant_drop_aggregate_need_migration() { @@ -124,6 +132,7 @@ fn test6_significant_insignificant_drop_aggregate_need_migration() { c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.1` would be dropped here alongside the closure // Since we are using a move closure here, both `t` and `t1` get moved // even though they are being used by ref inside the closure. @@ -142,6 +151,47 @@ fn test7_move_closures_non_copy_types_might_need_migration() { c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.1` would be dropped here alongside the closure +//~| NOTE: in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.1` would be dropped here alongside the closure + + +fn test8_drop_order_and_blocks() { + { + let tuple = + (String::from("foo"), String::from("bar")); + { + let c = || { + //~^ ERROR: drop order + //~| NOTE: for more information, see + //~| HELP: add a dummy let to cause `tuple` to be fully captured + tuple.0; + //~^ NOTE: in Rust 2018, closure captures all of `tuple`, but in Rust 2021, it only captures `tuple.0` + }; + + c(); + } + //~^ NOTE: in Rust 2018, `tuple` would be dropped here, but in Rust 2021, only `tuple.0` would be dropped here alongside the closure + } +} + +fn test9_drop_order_and_nested_closures() { + let tuple = + (String::from("foo"), String::from("bar")); + let b = || { + let c = || { + //~^ ERROR: drop order + //~| NOTE: for more information, see + //~| HELP: add a dummy let to cause `tuple` to be fully captured + tuple.0; + //~^ NOTE: in Rust 2018, closure captures all of `tuple`, but in Rust 2021, it only captures `tuple.0` + }; + + c(); + }; + //~^ NOTE: in Rust 2018, `tuple` would be dropped here, but in Rust 2021, only `tuple.0` would be dropped here alongside the closure + + b(); +} fn main() { test1_all_need_migration(); @@ -151,4 +201,6 @@ fn main() { test5_drop_non_drop_aggregate_need_migration(); test6_significant_insignificant_drop_aggregate_need_migration(); test7_move_closures_non_copy_types_might_need_migration(); + test8_drop_order_and_blocks(); + test9_drop_order_and_nested_closures(); } 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 f715ea9a48f7d..13eac4943a469 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 @@ -17,6 +17,13 @@ LL | | let _t2 = t2.0; LL | | LL | | }; | |_____^ +... +LL | } + | - + | | + | in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure + | in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.0` would be dropped here alongside the closure + | in Rust 2018, `t2` would be dropped here, but in Rust 2021, only `t2.0` would be dropped here alongside the closure | note: the lint level is defined here --> $DIR/significant_drop.rs:2:9 @@ -35,7 +42,7 @@ LL | ... error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/significant_drop.rs:47:13 + --> $DIR/significant_drop.rs:50:13 | LL | let c = || { | _____________^ @@ -51,6 +58,12 @@ LL | | LL | | let _t2 = t2; LL | | }; | |_____^ +... +LL | } + | - + | | + | in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure + | in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t`, `t1` to be fully captured @@ -64,7 +77,7 @@ LL | ... error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/significant_drop.rs:66:13 + --> $DIR/significant_drop.rs:71:13 | LL | let c = || { | _____________^ @@ -77,6 +90,9 @@ LL | | LL | | println!("{:?}", t1.1); LL | | }; | |_____^ +... +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -90,7 +106,7 @@ LL | ... error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/significant_drop.rs:85:13 + --> $DIR/significant_drop.rs:91:13 | LL | let c = || { | _____________^ @@ -102,6 +118,9 @@ LL | | let _t = t.0; LL | | LL | | }; | |_____^ +... +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -115,7 +134,7 @@ LL | ... error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/significant_drop.rs:102:13 + --> $DIR/significant_drop.rs:109:13 | LL | let c = || { | _____________^ @@ -127,6 +146,9 @@ LL | | let _t = t.0; LL | | LL | | }; | |_____^ +... +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -140,7 +162,7 @@ LL | ... error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/significant_drop.rs:117:13 + --> $DIR/significant_drop.rs:125:13 | LL | let c = || { | _____________^ @@ -152,6 +174,9 @@ LL | | let _t = t.1; LL | | LL | | }; | |_____^ +... +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.1` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -165,7 +190,7 @@ LL | ... error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/significant_drop.rs:134:13 + --> $DIR/significant_drop.rs:143:13 | LL | let c = move || { | _____________^ @@ -180,6 +205,12 @@ LL | | LL | | LL | | }; | |_____^ +... +LL | } + | - + | | + | in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.1` would be dropped here alongside the closure + | in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.1` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t1`, `t` to be fully captured @@ -192,5 +223,61 @@ LL | println!("{:?} {:?}", t1.1, t.1); LL | ... -error: aborting due to 7 previous errors +error: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/significant_drop.rs:163:21 + | +LL | let c = || { + | _____________________^ +LL | | +LL | | +LL | | +LL | | tuple.0; + | | ------- in Rust 2018, closure captures all of `tuple`, but in Rust 2021, it only captures `tuple.0` +LL | | +LL | | }; + | |_____________^ +... +LL | } + | - in Rust 2018, `tuple` would be dropped here, but in Rust 2021, only `tuple.0` would be dropped here alongside the closure + | + = note: for more information, see +help: add a dummy let to cause `tuple` to be fully captured + | +LL | let c = || { let _ = &tuple; +LL | +LL | +LL | +LL | tuple.0; +LL | + ... + +error: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/significant_drop.rs:181:17 + | +LL | let c = || { + | _________________^ +LL | | +LL | | +LL | | +LL | | tuple.0; + | | ------- in Rust 2018, closure captures all of `tuple`, but in Rust 2021, it only captures `tuple.0` +LL | | +LL | | }; + | |_________^ +... +LL | }; + | - in Rust 2018, `tuple` would be dropped here, but in Rust 2021, only `tuple.0` would be dropped here alongside the closure + | + = note: for more information, see +help: add a dummy let to cause `tuple` to be fully captured + | +LL | let c = || { let _ = &tuple; +LL | +LL | +LL | +LL | tuple.0; +LL | + ... + +error: aborting due to 9 previous errors From 36eb5442bd79b199b506e7912f72aade202a1ee1 Mon Sep 17 00:00:00 2001 From: Roxane Date: Wed, 7 Jul 2021 11:04:28 -0400 Subject: [PATCH 4/9] Add note clarifying why a closure no longer implements a trait --- compiler/rustc_typeck/src/check/upvar.rs | 16 ++++++++++++ .../migrations/auto_traits.fixed | 3 +++ .../migrations/auto_traits.rs | 3 +++ .../migrations/auto_traits.stderr | 25 +++++++++++++------ .../migrations/mir_calls_to_shims.fixed | 1 + .../migrations/mir_calls_to_shims.rs | 1 + .../migrations/mir_calls_to_shims.stderr | 7 ++++-- 7 files changed, 46 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index a5c4e161771a1..9806fd95c8f5c 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -535,6 +535,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { captured_names, )); } + + if reasons.contains("closure trait implementation") { + let closure_body_span = self.tcx.hir().span(body_id.hir_id); + let closure_ending_span = self.tcx.sess.source_map().guess_head_span(closure_body_span).shrink_to_lo(); + + let missing_trait = &reasons[..reasons.find("closure trait implementation").unwrap() - 1]; + + diagnostics_builder.span_label(closure_ending_span, format!("in Rust 2018, this closure would implement {} as `{}` implements {}, but in Rust 2021, this closure will no longer implement {} as {} does not implement {}", + missing_trait, + self.tcx.hir().name(*var_hir_id), + missing_trait, + missing_trait, + captured_names, + missing_trait, + )); + } } diagnostics_builder.note("for more information, see "); let closure_body_span = self.tcx.hir().span(body_id.hir_id); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed index ca55152cc2a83..4cc8a2b54be8e 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed @@ -13,6 +13,7 @@ fn test_send_trait() { let fptr = SendPointer(&mut f as *mut i32); thread::spawn(move || { let _ = &fptr; unsafe { //~^ ERROR: `Send` closure trait implementation + //~| NOTE: in Rust 2018, this closure would implement `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0 = 20; @@ -32,6 +33,7 @@ fn test_sync_trait() { let fptr = SyncPointer(f); thread::spawn(move || { let _ = &fptr; unsafe { //~^ ERROR: `Sync`, `Send` closure trait implementation + //~| NOTE: in Rust 2018, this closure would implement `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0.0 = 20; @@ -55,6 +57,7 @@ fn test_clone_trait() { let f = U(S(String::from("Hello World")), T(0)); let c = || { let _ = &f; //~^ ERROR: `Clone` closure trait implementation, and drop order + //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured let f_1 = f.1; diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs index 66c43cd865be2..a75c0aa527985 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs @@ -13,6 +13,7 @@ fn test_send_trait() { let fptr = SendPointer(&mut f as *mut i32); thread::spawn(move || unsafe { //~^ ERROR: `Send` closure trait implementation + //~| NOTE: in Rust 2018, this closure would implement `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0 = 20; @@ -32,6 +33,7 @@ fn test_sync_trait() { let fptr = SyncPointer(f); thread::spawn(move || unsafe { //~^ ERROR: `Sync`, `Send` closure trait implementation + //~| NOTE: in Rust 2018, this closure would implement `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0.0 = 20; @@ -55,6 +57,7 @@ fn test_clone_trait() { let f = U(S(String::from("Hello World")), T(0)); let c = || { //~^ ERROR: `Clone` closure trait implementation, and drop order + //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured let f_1 = f.1; diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr index 38f8976058d3d..c8867e1ac92a0 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr @@ -2,7 +2,10 @@ error: changes to closure capture in Rust 2021 will affect `Send` closure trait --> $DIR/auto_traits.rs:14:19 | LL | thread::spawn(move || unsafe { - | ___________________^ + | ^ - in Rust 2018, this closure would implement `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send` + | ___________________| + | | +LL | | LL | | LL | | LL | | @@ -24,15 +27,18 @@ LL | thread::spawn(move || { let _ = &fptr; unsafe { LL | LL | LL | -LL | *fptr.0 = 20; LL | +LL | *fptr.0 = 20; ... error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` closure trait implementation - --> $DIR/auto_traits.rs:33:19 + --> $DIR/auto_traits.rs:34:19 | LL | thread::spawn(move || unsafe { - | ___________________^ + | ^ - in Rust 2018, this closure would implement `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send` + | ___________________| + | | +LL | | LL | | LL | | LL | | @@ -49,15 +55,18 @@ LL | thread::spawn(move || { let _ = &fptr; unsafe { LL | LL | LL | -LL | *fptr.0.0 = 20; LL | +LL | *fptr.0.0 = 20; ... error: changes to closure capture in Rust 2021 will affect `Clone` closure trait implementation, and drop order - --> $DIR/auto_traits.rs:56:13 + --> $DIR/auto_traits.rs:58:13 | LL | let c = || { - | _____________^ + | ^ - in Rust 2018, this closure would implement `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` + | _____________| + | | +LL | | LL | | LL | | LL | | @@ -78,8 +87,8 @@ LL | let c = || { let _ = &f; LL | LL | LL | -LL | let f_1 = f.1; LL | +LL | let f_1 = f.1; ... error: aborting due to 3 previous errors diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed index cb3148214b4b8..f6e4f159ad08d 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed @@ -19,6 +19,7 @@ where let f = panic::AssertUnwindSafe(f); let result = panic::catch_unwind(move || { let _ = &f; //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` closure trait implementation + //~| NOTE: in Rust 2018, this closure would implement `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured f.0() diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs index f6f8ad2c52078..f6481d51fcd3f 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs @@ -19,6 +19,7 @@ where let f = panic::AssertUnwindSafe(f); let result = panic::catch_unwind(move || { //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` closure trait implementation + //~| NOTE: in Rust 2018, this closure would implement `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured f.0() diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr index 9a45e276fcdfc..bc8580b23b2d5 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr @@ -2,7 +2,10 @@ error: changes to closure capture in Rust 2021 will affect `UnwindSafe`, `RefUnw --> $DIR/mir_calls_to_shims.rs:20:38 | LL | let result = panic::catch_unwind(move || { - | ______________________________________^ + | ^ - in Rust 2018, this closure would implement `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe` + | ______________________________________| + | | +LL | | LL | | LL | | LL | | @@ -24,8 +27,8 @@ LL | let result = panic::catch_unwind(move || { let _ = &f; LL | LL | LL | -LL | f.0() LL | +LL | f.0() ... error: aborting due to previous error From 81b062ae889c6f0b156cb8eac1a0dcb97d1ed4bc Mon Sep 17 00:00:00 2001 From: Roxane Date: Wed, 7 Jul 2021 18:47:32 -0400 Subject: [PATCH 5/9] Fix wording --- compiler/rustc_typeck/src/check/upvar.rs | 33 ++- .../migrations/auto_traits.fixed | 12 +- .../migrations/auto_traits.rs | 12 +- .../migrations/auto_traits.stderr | 65 ++---- .../migrations/insignificant_drop.stderr | 181 ++++++--------- .../insignificant_drop_attr_migrations.stderr | 38 ++- .../migrations/migrations_rustfix.stderr | 19 +- .../migrations/mir_calls_to_shims.fixed | 4 +- .../migrations/mir_calls_to_shims.rs | 4 +- .../migrations/mir_calls_to_shims.stderr | 20 +- .../migrations/precise.stderr | 43 ++-- .../migrations/significant_drop.stderr | 216 +++++++----------- 12 files changed, 250 insertions(+), 397 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 9806fd95c8f5c..635b411f0e4f0 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -498,10 +498,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let local_def_id = closure_def_id.expect_local(); let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id); + let closure_span = self.tcx.hir().span(closure_hir_id); + let closure_head_span = self.tcx.sess.source_map().guess_head_span(closure_span); self.tcx.struct_span_lint_hir( lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, closure_hir_id, - span, + closure_head_span, |lint| { let mut diagnostics_builder = lint.build( format!( @@ -512,6 +514,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); for (var_hir_id, diagnostics_info) in need_migrations.iter() { let mut captured_names = format!(""); + // Label every Span which are responsible for the captured values for (captured_hir_id, captured_name) in diagnostics_info.iter() { if let Some(captured_hir_id) = captured_hir_id { let cause_span = self.tcx.hir().span(*captured_hir_id); @@ -527,6 +530,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + // Add a label pointing to where a closure and it's captured variables affected by drop order are dropped if reasons.contains("drop order") { let drop_location_span = drop_location_span(self.tcx, &closure_hir_id); @@ -536,13 +540,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } - if reasons.contains("closure trait implementation") { - let closure_body_span = self.tcx.hir().span(body_id.hir_id); - let closure_ending_span = self.tcx.sess.source_map().guess_head_span(closure_body_span).shrink_to_lo(); + // Add a label explaining why a closure no longer implements a trait + if reasons.contains("trait implementation") { + let missing_trait = &reasons[..reasons.find("trait implementation").unwrap() - 1]; - let missing_trait = &reasons[..reasons.find("closure trait implementation").unwrap() - 1]; - - diagnostics_builder.span_label(closure_ending_span, format!("in Rust 2018, this closure would implement {} as `{}` implements {}, but in Rust 2021, this closure will no longer implement {} as {} does not implement {}", + diagnostics_builder.span_label(closure_head_span, format!("in Rust 2018, this closure would implement {} as `{}` implements {}, but in Rust 2021, this closure would no longer implement {} as {} does not implement {}", missing_trait, self.tcx.hir().name(*var_hir_id), missing_trait, @@ -598,7 +600,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if auto_trait_reasons.len() > 0 { reasons = format!( - "{} closure trait implementation", + "{} trait implementation for closure", auto_trait_reasons.clone().into_iter().collect::>().join(", ") ); } @@ -1386,24 +1388,19 @@ fn drop_location_span(tcx: TyCtxt<'tcx>, hir_id: &hir::HirId) -> Span { let owner_id = tcx.hir().get_enclosing_scope(*hir_id).unwrap(); let owner_node = tcx.hir().get(owner_id); - match owner_node { + let owner_span = match owner_node { hir::Node::Item(item) => match item.kind { - hir::ItemKind::Fn(_, _, owner_id) => { - let owner_span = tcx.hir().span(owner_id.hir_id); - tcx.sess.source_map().end_point(owner_span) - } + hir::ItemKind::Fn(_, _, owner_id) => tcx.hir().span(owner_id.hir_id), _ => { bug!("Drop location span error: need to handle more ItemKind {:?}", item.kind); } }, - hir::Node::Block(block) => { - let owner_span = tcx.hir().span(block.hir_id); - tcx.sess.source_map().end_point(owner_span) - } + hir::Node::Block(block) => tcx.hir().span(block.hir_id), _ => { bug!("Drop location span error: need to handle more Node {:?}", owner_node); } - } + }; + tcx.sess.source_map().end_point(owner_span) } struct InferBorrowKind<'a, 'tcx> { diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed index 4cc8a2b54be8e..42863b440fc1d 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed @@ -12,8 +12,8 @@ fn test_send_trait() { let mut f = 10; let fptr = SendPointer(&mut f as *mut i32); thread::spawn(move || { let _ = &fptr; unsafe { - //~^ ERROR: `Send` closure trait implementation - //~| NOTE: in Rust 2018, this closure would implement `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send` + //~^ ERROR: `Send` trait implementation for closure + //~| NOTE: in Rust 2018, this closure would implement `Send` as `fptr` implements `Send`, but in Rust 2021, this closure would no longer implement `Send` as `fptr.0` does not implement `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0 = 20; @@ -32,8 +32,8 @@ fn test_sync_trait() { let f = CustomInt(&mut f as *mut i32); let fptr = SyncPointer(f); thread::spawn(move || { let _ = &fptr; unsafe { - //~^ ERROR: `Sync`, `Send` closure trait implementation - //~| NOTE: in Rust 2018, this closure would implement `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send` + //~^ ERROR: `Sync`, `Send` trait implementation for closure + //~| NOTE: in Rust 2018, this closure would implement `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure would no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0.0 = 20; @@ -56,8 +56,8 @@ impl Clone for U { fn test_clone_trait() { let f = U(S(String::from("Hello World")), T(0)); let c = || { let _ = &f; - //~^ ERROR: `Clone` closure trait implementation, and drop order - //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` + //~^ ERROR: `Clone` trait implementation for closure, and drop order + //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f.1` does not implement `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured let f_1 = f.1; diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs index a75c0aa527985..ae987f526d044 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs @@ -12,8 +12,8 @@ fn test_send_trait() { let mut f = 10; let fptr = SendPointer(&mut f as *mut i32); thread::spawn(move || unsafe { - //~^ ERROR: `Send` closure trait implementation - //~| NOTE: in Rust 2018, this closure would implement `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send` + //~^ ERROR: `Send` trait implementation for closure + //~| NOTE: in Rust 2018, this closure would implement `Send` as `fptr` implements `Send`, but in Rust 2021, this closure would no longer implement `Send` as `fptr.0` does not implement `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0 = 20; @@ -32,8 +32,8 @@ fn test_sync_trait() { let f = CustomInt(&mut f as *mut i32); let fptr = SyncPointer(f); thread::spawn(move || unsafe { - //~^ ERROR: `Sync`, `Send` closure trait implementation - //~| NOTE: in Rust 2018, this closure would implement `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send` + //~^ ERROR: `Sync`, `Send` trait implementation for closure + //~| NOTE: in Rust 2018, this closure would implement `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure would no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0.0 = 20; @@ -56,8 +56,8 @@ impl Clone for U { fn test_clone_trait() { let f = U(S(String::from("Hello World")), T(0)); let c = || { - //~^ ERROR: `Clone` closure trait implementation, and drop order - //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` + //~^ ERROR: `Clone` trait implementation for closure, and drop order + //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f.1` does not implement `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured let f_1 = f.1; diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr index c8867e1ac92a0..2af85852c01a0 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr @@ -1,19 +1,11 @@ -error: changes to closure capture in Rust 2021 will affect `Send` closure trait implementation +error: changes to closure capture in Rust 2021 will affect `Send` trait implementation for closure --> $DIR/auto_traits.rs:14:19 | -LL | thread::spawn(move || unsafe { - | ^ - in Rust 2018, this closure would implement `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send` - | ___________________| - | | -LL | | -LL | | -LL | | -LL | | -LL | | *fptr.0 = 20; - | | ------- in Rust 2018, closure captures all of `fptr`, but in Rust 2021, it only captures `fptr.0` -LL | | -LL | | }); - | |_____^ +LL | thread::spawn(move || unsafe { + | ^^^^^^^^^^^^^^ in Rust 2018, this closure would implement `Send` as `fptr` implements `Send`, but in Rust 2021, this closure would no longer implement `Send` as `fptr.0` does not implement `Send` +... +LL | *fptr.0 = 20; + | ------- in Rust 2018, closure captures all of `fptr`, but in Rust 2021, it only captures `fptr.0` | note: the lint level is defined here --> $DIR/auto_traits.rs:2:9 @@ -31,22 +23,14 @@ LL | LL | *fptr.0 = 20; ... -error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` closure trait implementation +error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure --> $DIR/auto_traits.rs:34:19 | -LL | thread::spawn(move || unsafe { - | ^ - in Rust 2018, this closure would implement `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send` - | ___________________| - | | -LL | | -LL | | -LL | | -LL | | -LL | | *fptr.0.0 = 20; - | | --------- in Rust 2018, closure captures all of `fptr`, but in Rust 2021, it only captures `fptr.0.0` -LL | | -LL | | }); - | |_____^ +LL | thread::spawn(move || unsafe { + | ^^^^^^^^^^^^^^ in Rust 2018, this closure would implement `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure would no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send` +... +LL | *fptr.0.0 = 20; + | --------- in Rust 2018, closure captures all of `fptr`, but in Rust 2021, it only captures `fptr.0.0` | = note: for more information, see help: add a dummy let to cause `fptr` to be fully captured @@ -59,26 +43,17 @@ LL | LL | *fptr.0.0 = 20; ... -error: changes to closure capture in Rust 2021 will affect `Clone` closure trait implementation, and drop order +error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure, and drop order --> $DIR/auto_traits.rs:58:13 | -LL | let c = || { - | ^ - in Rust 2018, this closure would implement `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` - | _____________| - | | -LL | | -LL | | -LL | | -LL | | -LL | | let f_1 = f.1; - | | --- in Rust 2018, closure captures all of `f`, but in Rust 2021, it only captures `f.1` -LL | | -LL | | println!("{:?}", f_1.0); -LL | | }; - | |_____^ +LL | let c = || { + | ^^ in Rust 2018, this closure would implement `Clone` as `f` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f.1` does not implement `Clone` +... +LL | let f_1 = f.1; + | --- in Rust 2018, closure captures all of `f`, but in Rust 2021, it only captures `f.1` ... -LL | } - | - in Rust 2018, `f` would be dropped here, but in Rust 2021, only `f.1` would be dropped here alongside the closure +LL | } + | - in Rust 2018, `f` would be dropped here, but in Rust 2021, only `f.1` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `f` to be fully captured 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 e7b2cd1c55347..e9e4794cff5f7 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 @@ -1,30 +1,24 @@ error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/insignificant_drop.rs:15:13 | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | -LL | | let _t = t.0; - | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` -LL | | -LL | | let _t1 = t1.0; - | | ---- in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.0` -LL | | -LL | | let _t2 = t2.0; - | | ---- in Rust 2018, closure captures all of `t2`, but in Rust 2021, it only captures `t2.0` -LL | | -LL | | }; - | |_____^ +LL | let c = || { + | ^^ ... -LL | } - | - - | | - | in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure - | in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.0` would be dropped here alongside the closure - | in Rust 2018, `t2` would be dropped here, but in Rust 2021, only `t2.0` would be dropped here alongside the closure +LL | let _t = t.0; + | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +LL | +LL | let _t1 = t1.0; + | ---- in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.0` +LL | +LL | let _t2 = t2.0; + | ---- in Rust 2018, closure captures all of `t2`, but in Rust 2021, it only captures `t2.0` +... +LL | } + | - + | | + | in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure + | in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.0` would be dropped here alongside the closure + | in Rust 2018, `t2` would be dropped here, but in Rust 2021, only `t2.0` would be dropped here alongside the closure | note: the lint level is defined here --> $DIR/insignificant_drop.rs:3:9 @@ -45,26 +39,20 @@ LL | let _t = t.0; error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/insignificant_drop.rs:41:13 | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.0; - | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` -LL | | -LL | | let _t1 = t1.0; - | | ---- in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.0` -LL | | -LL | | let _t2 = t2; -LL | | }; - | |_____^ +LL | let c = || { + | ^^ ... -LL | } - | - - | | - | in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure - | in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.0` would be dropped here alongside the closure +LL | let _t = t.0; + | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +LL | +LL | let _t1 = t1.0; + | ---- in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.0` +... +LL | } + | - + | | + | in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure + | in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t`, `t1` to be fully captured @@ -80,20 +68,14 @@ LL | error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/insignificant_drop.rs:62:13 | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.0; - | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` -LL | | -LL | | println!("{}", t1.1); -LL | | }; - | |_____^ +LL | let c = || { + | ^^ +... +LL | let _t = t.0; + | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` ... -LL | } - | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -109,20 +91,14 @@ LL | error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/insignificant_drop.rs:83:13 | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.0; - | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` -LL | | -LL | | let _t1 = t1.0; -LL | | }; - | |_____^ +LL | let c = || { + | ^^ ... -LL | } - | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure +LL | let _t = t.0; + | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +... +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -138,20 +114,14 @@ LL | error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/insignificant_drop.rs:104:13 | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.0; - | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` -LL | | -LL | | let _s = s.0; -LL | | }; - | |_____^ +LL | let c = || { + | ^^ +... +LL | let _t = t.0; + | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` ... -LL | } - | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -167,25 +137,19 @@ LL | error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/insignificant_drop.rs:122:13 | -LL | let c = move || { - | _____________^ -LL | | -LL | | -LL | | -LL | | println!("{} {}", t1.1, t.1); - | | ---- --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.1` - | | | - | | in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.1` -LL | | -LL | | -LL | | }; - | |_____^ +LL | let c = move || { + | ^^^^^^^ ... -LL | } - | - - | | - | in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.1` would be dropped here alongside the closure - | in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.1` would be dropped here alongside the closure +LL | println!("{} {}", t1.1, t.1); + | ---- --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.1` + | | + | in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.1` +... +LL | } + | - + | | + | in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.1` would be dropped here alongside the closure + | in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.1` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t1`, `t` to be fully captured @@ -201,19 +165,14 @@ LL | error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/insignificant_drop.rs:142:13 | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.0; - | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` -LL | | -LL | | }; - | |_____^ +LL | let c = || { + | ^^ +... +LL | let _t = t.0; + | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` ... -LL | } - | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t` to be fully captured diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr index 97ff0409d0a63..1e97ca34d162e 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr @@ -1,19 +1,14 @@ error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/insignificant_drop_attr_migrations.rs:37:13 | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.0; - | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` -LL | | -LL | | }; - | |_____^ +LL | let c = || { + | ^^ ... -LL | } - | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure +LL | let _t = t.0; + | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +... +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure | note: the lint level is defined here --> $DIR/insignificant_drop_attr_migrations.rs:3:9 @@ -34,19 +29,14 @@ LL | error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/insignificant_drop_attr_migrations.rs:57:13 | -LL | let c = move || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.1; - | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.1` -LL | | -LL | | }; - | |_____^ +LL | let c = move || { + | ^^^^^^^ +... +LL | let _t = t.1; + | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.1` ... -LL | } - | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.1` would be dropped here alongside the closure +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.1` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t` to be fully captured 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 index 09bae6d3f1344..f8f72d1580ca9 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr @@ -1,19 +1,14 @@ error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/migrations_rustfix.rs:19:13 | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.0; - | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` -LL | | -LL | | }; - | |_____^ +LL | let c = || { + | ^^ ... -LL | } - | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure +LL | let _t = t.0; + | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +... +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure | note: the lint level is defined here --> $DIR/migrations_rustfix.rs:2:9 diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed index f6e4f159ad08d..f24804018cd85 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed @@ -18,8 +18,8 @@ where { let f = panic::AssertUnwindSafe(f); let result = panic::catch_unwind(move || { let _ = &f; - //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` closure trait implementation - //~| NOTE: in Rust 2018, this closure would implement `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe` + //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` trait implementation for closure + //~| NOTE: in Rust 2018, this closure would implement `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure would no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured f.0() diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs index f6481d51fcd3f..6a6a51c51322d 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs @@ -18,8 +18,8 @@ where { let f = panic::AssertUnwindSafe(f); let result = panic::catch_unwind(move || { - //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` closure trait implementation - //~| NOTE: in Rust 2018, this closure would implement `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe` + //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` trait implementation for closure + //~| NOTE: in Rust 2018, this closure would implement `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure would no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured f.0() diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr index bc8580b23b2d5..6ee0d0d252aba 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr @@ -1,19 +1,11 @@ -error: changes to closure capture in Rust 2021 will affect `UnwindSafe`, `RefUnwindSafe` closure trait implementation +error: changes to closure capture in Rust 2021 will affect `UnwindSafe`, `RefUnwindSafe` trait implementation for closure --> $DIR/mir_calls_to_shims.rs:20:38 | -LL | let result = panic::catch_unwind(move || { - | ^ - in Rust 2018, this closure would implement `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe` - | ______________________________________| - | | -LL | | -LL | | -LL | | -LL | | -LL | | f.0() - | | --- in Rust 2018, closure captures all of `f`, but in Rust 2021, it only captures `f.0` -LL | | -LL | | }); - | |_____^ +LL | let result = panic::catch_unwind(move || { + | ^^^^^^^ in Rust 2018, this closure would implement `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure would no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe` +... +LL | f.0() + | --- in Rust 2018, closure captures all of `f`, but in Rust 2021, it only captures `f.0` | note: the lint level is defined here --> $DIR/mir_calls_to_shims.rs:3:9 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 7bec8ef06fce3..153c0d6b68671 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/precise.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/precise.stderr @@ -1,18 +1,14 @@ error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/precise.rs:19:13 | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | let _t = t.0; - | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` -LL | | let _t = &t.1; -LL | | }; - | |_____^ +LL | let c = || { + | ^^ ... -LL | } - | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure +LL | let _t = t.0; + | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +... +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure | note: the lint level is defined here --> $DIR/precise.rs:3:9 @@ -33,21 +29,18 @@ LL | }; error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/precise.rs:41:13 | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | let _x = u.0.0; - | | ----- in Rust 2018, closure captures all of `u`, but in Rust 2021, it only captures `u.0.0` -LL | | let _x = u.0.1; - | | ----- in Rust 2018, closure captures all of `u`, but in Rust 2021, it only captures `u.0.1` -LL | | let _x = u.1.0; - | | ----- in Rust 2018, closure captures all of `u`, but in Rust 2021, it only captures `u.1.0` -LL | | }; - | |_____^ +LL | let c = || { + | ^^ +... +LL | let _x = u.0.0; + | ----- in Rust 2018, closure captures all of `u`, but in Rust 2021, it only captures `u.0.0` +LL | let _x = u.0.1; + | ----- in Rust 2018, closure captures all of `u`, but in Rust 2021, it only captures `u.0.1` +LL | let _x = u.1.0; + | ----- in Rust 2018, closure captures all of `u`, but in Rust 2021, it only captures `u.1.0` ... -LL | } - | - in Rust 2018, `u` would be dropped here, but in Rust 2021, only `u.0.1`, `u.0.0`, `u.1.0` would be dropped here alongside the closure +LL | } + | - in Rust 2018, `u` would be dropped here, but in Rust 2021, only `u.0.1`, `u.0.0`, `u.1.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `u` to be fully captured 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 13eac4943a469..b2b9ae8fd12f5 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 @@ -1,29 +1,24 @@ error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/significant_drop.rs:25:13 | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.0; - | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` -LL | | -LL | | let _t1 = t1.0; - | | ---- in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.0` -LL | | -LL | | let _t2 = t2.0; - | | ---- in Rust 2018, closure captures all of `t2`, but in Rust 2021, it only captures `t2.0` -LL | | -LL | | }; - | |_____^ +LL | let c = || { + | ^^ ... -LL | } - | - - | | - | in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure - | in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.0` would be dropped here alongside the closure - | in Rust 2018, `t2` would be dropped here, but in Rust 2021, only `t2.0` would be dropped here alongside the closure +LL | let _t = t.0; + | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +LL | +LL | let _t1 = t1.0; + | ---- in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.0` +LL | +LL | let _t2 = t2.0; + | ---- in Rust 2018, closure captures all of `t2`, but in Rust 2021, it only captures `t2.0` +... +LL | } + | - + | | + | in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure + | in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.0` would be dropped here alongside the closure + | in Rust 2018, `t2` would be dropped here, but in Rust 2021, only `t2.0` would be dropped here alongside the closure | note: the lint level is defined here --> $DIR/significant_drop.rs:2:9 @@ -44,26 +39,20 @@ LL | error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/significant_drop.rs:50:13 | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.0; - | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` -LL | | -LL | | let _t1 = t1.0; - | | ---- in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.0` -LL | | -LL | | let _t2 = t2; -LL | | }; - | |_____^ +LL | let c = || { + | ^^ ... -LL | } - | - - | | - | in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure - | in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.0` would be dropped here alongside the closure +LL | let _t = t.0; + | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +LL | +LL | let _t1 = t1.0; + | ---- in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.0` +... +LL | } + | - + | | + | in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure + | in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t`, `t1` to be fully captured @@ -79,20 +68,14 @@ LL | error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/significant_drop.rs:71:13 | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.0; - | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` -LL | | -LL | | println!("{:?}", t1.1); -LL | | }; - | |_____^ +LL | let c = || { + | ^^ +... +LL | let _t = t.0; + | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` ... -LL | } - | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -108,19 +91,14 @@ LL | error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/significant_drop.rs:91:13 | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.0; - | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` -LL | | -LL | | }; - | |_____^ +LL | let c = || { + | ^^ +... +LL | let _t = t.0; + | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` ... -LL | } - | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -136,19 +114,14 @@ LL | error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/significant_drop.rs:109:13 | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.0; - | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` -LL | | -LL | | }; - | |_____^ +LL | let c = || { + | ^^ ... -LL | } - | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure +LL | let _t = t.0; + | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` +... +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -164,19 +137,14 @@ LL | error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/significant_drop.rs:125:13 | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.1; - | | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.1` -LL | | -LL | | }; - | |_____^ +LL | let c = || { + | ^^ ... -LL | } - | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.1` would be dropped here alongside the closure +LL | let _t = t.1; + | --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.1` +... +LL | } + | - in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.1` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -192,25 +160,19 @@ LL | error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/significant_drop.rs:143:13 | -LL | let c = move || { - | _____________^ -LL | | -LL | | -LL | | -LL | | println!("{:?} {:?}", t1.1, t.1); - | | ---- --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.1` - | | | - | | in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.1` -LL | | -LL | | -LL | | }; - | |_____^ +LL | let c = move || { + | ^^^^^^^ +... +LL | println!("{:?} {:?}", t1.1, t.1); + | ---- --- in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.1` + | | + | in Rust 2018, closure captures all of `t1`, but in Rust 2021, it only captures `t1.1` ... -LL | } - | - - | | - | in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.1` would be dropped here alongside the closure - | in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.1` would be dropped here alongside the closure +LL | } + | - + | | + | in Rust 2018, `t1` would be dropped here, but in Rust 2021, only `t1.1` would be dropped here alongside the closure + | in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.1` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `t1`, `t` to be fully captured @@ -226,19 +188,14 @@ LL | error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/significant_drop.rs:163:21 | -LL | let c = || { - | _____________________^ -LL | | -LL | | -LL | | -LL | | tuple.0; - | | ------- in Rust 2018, closure captures all of `tuple`, but in Rust 2021, it only captures `tuple.0` -LL | | -LL | | }; - | |_____________^ +LL | let c = || { + | ^^ +... +LL | tuple.0; + | ------- in Rust 2018, closure captures all of `tuple`, but in Rust 2021, it only captures `tuple.0` ... -LL | } - | - in Rust 2018, `tuple` would be dropped here, but in Rust 2021, only `tuple.0` would be dropped here alongside the closure +LL | } + | - in Rust 2018, `tuple` would be dropped here, but in Rust 2021, only `tuple.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `tuple` to be fully captured @@ -254,19 +211,14 @@ LL | error: changes to closure capture in Rust 2021 will affect drop order --> $DIR/significant_drop.rs:181:17 | -LL | let c = || { - | _________________^ -LL | | -LL | | -LL | | -LL | | tuple.0; - | | ------- in Rust 2018, closure captures all of `tuple`, but in Rust 2021, it only captures `tuple.0` -LL | | -LL | | }; - | |_________^ +LL | let c = || { + | ^^ +... +LL | tuple.0; + | ------- in Rust 2018, closure captures all of `tuple`, but in Rust 2021, it only captures `tuple.0` ... -LL | }; - | - in Rust 2018, `tuple` would be dropped here, but in Rust 2021, only `tuple.0` would be dropped here alongside the closure +LL | }; + | - in Rust 2018, `tuple` would be dropped here, but in Rust 2021, only `tuple.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `tuple` to be fully captured From 59f634bc2d9188375ef51944b16e0450c638afdb Mon Sep 17 00:00:00 2001 From: Roxane Date: Wed, 7 Jul 2021 19:08:04 -0400 Subject: [PATCH 6/9] Update comments --- compiler/rustc_typeck/src/check/upvar.rs | 26 ++++++++++++++---------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 635b411f0e4f0..11638720e8d2b 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -616,7 +616,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { reasons } - /// Returns true if migration is needed for trait for the provided var_hir_id + /// Returns a tuple that contains the hir_id pointing to the use that resulted in the + /// corresponding place being captured and a String which contains the captured value's name + /// (i.e: a.b.c) if migration is needed for trait for the provided var_hir_id, otherwise returns None fn need_2229_migrations_for_trait( &self, min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, @@ -693,12 +695,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// captured by the closure when `capture_disjoint_fields` is enabled and auto-traits /// differ between the root variable and the captured paths. /// - /// The output list would include a root variable if: - /// - It would have been captured into the closure when `capture_disjoint_fields` wasn't - /// enabled, **and** - /// - It wasn't completely captured by the closure, **and** - /// - One of the paths captured does not implement all the auto-traits its root variable - /// implements. + /// Returns a tuple containing a HashSet of traits that not implemented by the captured fields + /// of a root variables that has the provided var_hir_id and a HashSet of tuples that contains + /// the hir_id pointing to the use that resulted in the corresponding place being captured and + /// a String which contains the captured value's name (i.e: a.b.c) if migration is needed for + /// trait for the provided var_hir_id, otherwise returns None fn compute_2229_migrations_for_trait( &self, min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, @@ -788,8 +789,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// - It wasn't completely captured by the closure, **and** /// - One of the paths starting at this root variable, that is not captured needs Drop. /// - /// This function only returns true for significant drops. A type is considerent to have a - /// significant drop if it's Drop implementation is not annotated by `rustc_insignificant_dtor`. + /// This function only returns a HashSet of tuples for significant drops. The returned HashSet + /// of tuples contains the hir_id pointing to the use that resulted in the corresponding place + /// being captured anda String which contains the captured value's name (i.e: a.b.c) fn compute_2229_migrations_for_drop( &self, closure_def_id: DefId, @@ -871,8 +873,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// - One of the paths captured does not implement all the auto-traits its root variable /// implements. /// - /// Returns a tuple containing a vector of HirIds as well as a String containing the reason - /// why root variables whose HirId is contained in the vector should be fully captured. + /// Returns a tuple containing a vector of tuples of HirIds and a HashSet of tuples that contains + /// the hir_id pointing to the use that resulted in the corresponding place being captured and + /// a String which contains the captured value's name (i.e: a.b.c), as well as a String + /// containing the reason why root variables whose HirId is contained in the vector should fn compute_2229_migrations( &self, closure_def_id: DefId, From ca443729575da9c81e47da80adcbf1b14fa1e09b Mon Sep 17 00:00:00 2001 From: Roxane Date: Thu, 8 Jul 2021 17:04:58 -0400 Subject: [PATCH 7/9] Handle multi diagnostics --- compiler/rustc_typeck/src/check/upvar.rs | 352 +++++++++--------- .../migrations/multi_diagnostics.fixed | 138 +++++++ .../migrations/multi_diagnostics.rs | 138 +++++++ .../migrations/multi_diagnostics.stderr | 134 +++++++ .../migrations/precise.fixed | 12 + .../migrations/precise.rs | 12 + .../migrations/precise.stderr | 22 +- 7 files changed, 624 insertions(+), 184 deletions(-) create mode 100644 src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed create mode 100644 src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 11638720e8d2b..2b82b4dff2e5a 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -50,6 +50,7 @@ use rustc_span::sym; use rustc_span::{MultiSpan, Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; +use rustc_data_structures::stable_map::FxHashMap; use rustc_data_structures::stable_set::FxHashSet; use rustc_index::vec::Idx; use rustc_target::abi::VariantIdx; @@ -81,6 +82,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } +/// Intermediate format to store the hir_id pointing to the use that resulted in the +/// corresponding place being captured and a String which contains the captured value's +/// name (i.e: a.b.c) +type CapturesInfo = (Option, String); + +/// Intermediate format to store information needed to generate migration lint. The tuple +/// contains the hir_id pointing to the use that resulted in the +/// corresponding place being captured, a String which contains the captured value's +/// name (i.e: a.b.c) and a String which contains the reason why migration is needed for that +/// capture +type MigrationNeededForCapture = (Option, String, String); + +/// Intermediate format to store the hir id of the root variable and a HashSet containing +/// information on why the root variable should be fully captured +type MigrationDiagnosticInfo = (hir::HirId, FxHashSet); + struct InferBorrowKindVisitor<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, } @@ -513,45 +530,41 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .as_str(), ); for (var_hir_id, diagnostics_info) in need_migrations.iter() { - let mut captured_names = format!(""); - // Label every Span which are responsible for the captured values - for (captured_hir_id, captured_name) in diagnostics_info.iter() { + // Labels all the usage of the captured variable and why they are responsible + // for migration being needed + for (captured_hir_id, captured_name, reasons) in diagnostics_info.iter() { if let Some(captured_hir_id) = captured_hir_id { let cause_span = self.tcx.hir().span(*captured_hir_id); diagnostics_builder.span_label(cause_span, format!("in Rust 2018, closure captures all of `{}`, but in Rust 2021, it only captures `{}`", self.tcx.hir().name(*var_hir_id), captured_name, )); - if captured_names == "" { - captured_names = format!("`{}`", captured_name); - } else { - captured_names = format!("{}, `{}`", captured_names, captured_name); - } } - } - // Add a label pointing to where a closure and it's captured variables affected by drop order are dropped - if reasons.contains("drop order") { - let drop_location_span = drop_location_span(self.tcx, &closure_hir_id); + // Add a label pointing to where a captured variable affected by drop order + // is dropped + if reasons.contains("drop order") { + let drop_location_span = drop_location_span(self.tcx, &closure_hir_id); - diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` would be dropped here, but in Rust 2021, only {} would be dropped here alongside the closure", - self.tcx.hir().name(*var_hir_id), - captured_names, - )); - } + diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` would be dropped here, but in Rust 2021, only `{}` would be dropped here alongside the closure", + self.tcx.hir().name(*var_hir_id), + captured_name, + )); + } + + // Add a label explaining why a closure no longer implements a trait + if reasons.contains("trait implementation") { + let missing_trait = &reasons[..reasons.find("trait implementation").unwrap() - 1]; - // Add a label explaining why a closure no longer implements a trait - if reasons.contains("trait implementation") { - let missing_trait = &reasons[..reasons.find("trait implementation").unwrap() - 1]; - - diagnostics_builder.span_label(closure_head_span, format!("in Rust 2018, this closure would implement {} as `{}` implements {}, but in Rust 2021, this closure would no longer implement {} as {} does not implement {}", - missing_trait, - self.tcx.hir().name(*var_hir_id), - missing_trait, - missing_trait, - captured_names, - missing_trait, - )); + diagnostics_builder.span_label(closure_head_span, format!("in Rust 2018, this closure would implement {} as `{}` implements {}, but in Rust 2021, this closure would no longer implement {} as `{}` does not implement {}", + missing_trait, + self.tcx.hir().name(*var_hir_id), + missing_trait, + missing_trait, + captured_name, + missing_trait, + )); + } } } diagnostics_builder.note("for more information, see "); @@ -616,16 +629,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { reasons } - /// Returns a tuple that contains the hir_id pointing to the use that resulted in the - /// corresponding place being captured and a String which contains the captured value's name - /// (i.e: a.b.c) if migration is needed for trait for the provided var_hir_id, otherwise returns None - fn need_2229_migrations_for_trait( + /// Figures out the list of root variables (and their types) that aren't completely + /// captured by the closure when `capture_disjoint_fields` is enabled and auto-traits + /// differ between the root variable and the captured paths. + /// + /// Returns a tuple containing a HashMap of CapturesInfo that maps to a HashSet of trait names + /// if migration is needed for traits for the provided var_hir_id, otherwise returns None + fn compute_2229_migrations_for_trait( &self, min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, var_hir_id: hir::HirId, - check_trait: Option, closure_clause: hir::CaptureBy, - ) -> Option<(Option, String)> { + ) -> Option>> { + let auto_traits_def_id = vec![ + self.tcx.lang_items().clone_trait(), + self.tcx.lang_items().sync_trait(), + self.tcx.get_diagnostic_item(sym::send_trait), + self.tcx.lang_items().unpin_trait(), + self.tcx.get_diagnostic_item(sym::unwind_safe_trait), + self.tcx.get_diagnostic_item(sym::ref_unwind_safe_trait), + ]; + let auto_traits = + vec!["`Clone`", "`Sync`", "`Send`", "`Unpin`", "`UnwindSafe`", "`RefUnwindSafe`"]; + let root_var_min_capture_list = if let Some(root_var_min_capture_list) = min_captures.and_then(|m| m.get(&var_hir_id)) { @@ -650,19 +676,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - let obligation_should_hold = check_trait - .map(|check_trait| { - self.infcx - .type_implements_trait( - check_trait, - ty, - self.tcx.mk_substs_trait(ty, &[]), - self.param_env, - ) - .must_apply_modulo_regions() - }) - .unwrap_or(false); + let mut obligations_should_hold = Vec::new(); + // Checks if a root variable implements any of the auto traits + for check_trait in auto_traits_def_id.iter() { + obligations_should_hold.push( + check_trait + .map(|check_trait| { + self.infcx + .type_implements_trait( + check_trait, + ty, + self.tcx.mk_substs_trait(ty, &[]), + self.param_env, + ) + .must_apply_modulo_regions() + }) + .unwrap_or(false), + ); + } + let mut problematic_captures = FxHashMap::default(); // Check whether captured fields also implement the trait for capture in root_var_min_capture_list.iter() { let ty = apply_capture_kind_on_capture_ty( @@ -671,112 +704,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { capture.info.capture_kind, ); - let obligation_holds_for_capture = check_trait - .map(|check_trait| { - self.infcx - .type_implements_trait( - check_trait, - ty, - self.tcx.mk_substs_trait(ty, &[]), - self.param_env, - ) - .must_apply_modulo_regions() - }) - .unwrap_or(false); - - if !obligation_holds_for_capture && obligation_should_hold { - return Some((capture.info.path_expr_id, capture.to_string(self.tcx))); + // Checks if a capture implements any of the auto traits + let mut obligations_holds_for_capture = Vec::new(); + for check_trait in auto_traits_def_id.iter() { + obligations_holds_for_capture.push( + check_trait + .map(|check_trait| { + self.infcx + .type_implements_trait( + check_trait, + ty, + self.tcx.mk_substs_trait(ty, &[]), + self.param_env, + ) + .must_apply_modulo_regions() + }) + .unwrap_or(false), + ); } - } - None - } - - /// Figures out the list of root variables (and their types) that aren't completely - /// captured by the closure when `capture_disjoint_fields` is enabled and auto-traits - /// differ between the root variable and the captured paths. - /// - /// Returns a tuple containing a HashSet of traits that not implemented by the captured fields - /// of a root variables that has the provided var_hir_id and a HashSet of tuples that contains - /// the hir_id pointing to the use that resulted in the corresponding place being captured and - /// a String which contains the captured value's name (i.e: a.b.c) if migration is needed for - /// trait for the provided var_hir_id, otherwise returns None - fn compute_2229_migrations_for_trait( - &self, - min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, - var_hir_id: hir::HirId, - closure_clause: hir::CaptureBy, - ) -> Option<(FxHashSet<&str>, FxHashSet<(Option, String)>)> { - let tcx = self.infcx.tcx; - // Check whether catpured fields also implement the trait - let mut auto_trait_reasons = FxHashSet::default(); - let mut diagnostics_info = FxHashSet::default(); - - if let Some(info) = self.need_2229_migrations_for_trait( - min_captures, - var_hir_id, - tcx.lang_items().clone_trait(), - closure_clause, - ) { - auto_trait_reasons.insert("`Clone`"); - diagnostics_info.insert(info); - } + let mut capture_problems = FxHashSet::default(); - if let Some(info) = self.need_2229_migrations_for_trait( - min_captures, - var_hir_id, - tcx.lang_items().sync_trait(), - closure_clause, - ) { - auto_trait_reasons.insert("`Sync`"); - diagnostics_info.insert(info); - } - - if let Some(info) = self.need_2229_migrations_for_trait( - min_captures, - var_hir_id, - tcx.get_diagnostic_item(sym::send_trait), - closure_clause, - ) { - auto_trait_reasons.insert("`Send`"); - diagnostics_info.insert(info); - } - - if let Some(info) = self.need_2229_migrations_for_trait( - min_captures, - var_hir_id, - tcx.lang_items().unpin_trait(), - closure_clause, - ) { - auto_trait_reasons.insert("`Unpin`"); - diagnostics_info.insert(info); - } - - if let Some(info) = self.need_2229_migrations_for_trait( - min_captures, - var_hir_id, - tcx.get_diagnostic_item(sym::unwind_safe_trait), - closure_clause, - ) { - auto_trait_reasons.insert("`UnwindSafe`"); - diagnostics_info.insert(info); - } + // Checks if for any of the auto traits, one or more trait is implemented + // by the root variable but not by the capture + for (idx, _) in obligations_should_hold.iter().enumerate() { + if !obligations_holds_for_capture[idx] && obligations_should_hold[idx] { + capture_problems.insert(auto_traits[idx]); + } + } - if let Some(info) = self.need_2229_migrations_for_trait( - min_captures, - var_hir_id, - tcx.get_diagnostic_item(sym::ref_unwind_safe_trait), - closure_clause, - ) { - auto_trait_reasons.insert("`RefUnwindSafe`"); - diagnostics_info.insert(info); + if capture_problems.len() > 0 { + problematic_captures.insert( + (capture.info.path_expr_id, capture.to_string(self.tcx)), + capture_problems, + ); + } } - - if auto_trait_reasons.len() > 0 { - return Some((auto_trait_reasons, diagnostics_info)); + if problematic_captures.len() > 0 { + return Some(problematic_captures); } - - return None; + None } /// Figures out the list of root variables (and their types) that aren't completely @@ -789,9 +756,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// - It wasn't completely captured by the closure, **and** /// - One of the paths starting at this root variable, that is not captured needs Drop. /// - /// This function only returns a HashSet of tuples for significant drops. The returned HashSet - /// of tuples contains the hir_id pointing to the use that resulted in the corresponding place - /// being captured anda String which contains the captured value's name (i.e: a.b.c) + /// This function only returns a HashSet of CapturesInfo for significant drops. If there + /// are no significant drops than None is returned fn compute_2229_migrations_for_drop( &self, closure_def_id: DefId, @@ -799,7 +765,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, closure_clause: hir::CaptureBy, var_hir_id: hir::HirId, - ) -> Option, String)>> { + ) -> Option> { let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id)); if !ty.has_significant_drop(self.tcx, self.tcx.param_env(closure_def_id.expect_local())) { @@ -873,17 +839,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// - One of the paths captured does not implement all the auto-traits its root variable /// implements. /// - /// Returns a tuple containing a vector of tuples of HirIds and a HashSet of tuples that contains - /// the hir_id pointing to the use that resulted in the corresponding place being captured and - /// a String which contains the captured value's name (i.e: a.b.c), as well as a String + /// Returns a tuple containing a vector of MigrationDiagnosticInfo, as well as a String /// containing the reason why root variables whose HirId is contained in the vector should + /// be captured fn compute_2229_migrations( &self, closure_def_id: DefId, closure_span: Span, closure_clause: hir::CaptureBy, min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, - ) -> (Vec<(hir::HirId, FxHashSet<(Option, String)>)>, String) { + ) -> (Vec, String) { let upvars = if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { upvars } else { @@ -891,42 +856,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let mut need_migrations = Vec::new(); - let mut auto_trait_reasons = FxHashSet::default(); - let mut drop_reorder_reason = false; + let mut auto_trait_migration_reasons = FxHashSet::default(); + let mut drop_migration_needed = false; // Perform auto-trait analysis for (&var_hir_id, _) in upvars.iter() { - let mut need_migration = false; let mut responsible_captured_hir_ids = FxHashSet::default(); - if let Some((trait_migration_cause, diagnostics_info)) = + let auto_trait_diagnostic = if let Some(diagnostics_info) = self.compute_2229_migrations_for_trait(min_captures, var_hir_id, closure_clause) { - need_migration = true; - auto_trait_reasons.extend(trait_migration_cause); - responsible_captured_hir_ids.extend(diagnostics_info); + diagnostics_info + } else { + FxHashMap::default() + }; + + let drop_reorder_diagnostic = if let Some(diagnostics_info) = self + .compute_2229_migrations_for_drop( + closure_def_id, + closure_span, + min_captures, + closure_clause, + var_hir_id, + ) { + drop_migration_needed = true; + diagnostics_info + } else { + FxHashSet::default() + }; + + // Combine all the captures responsible for needing migrations into one HashSet + let mut capture_disagnostic = drop_reorder_diagnostic.clone(); + for key in auto_trait_diagnostic.keys() { + capture_disagnostic.insert(key.clone()); } - if let Some(diagnostics_info) = self.compute_2229_migrations_for_drop( - closure_def_id, - closure_span, - min_captures, - closure_clause, - var_hir_id, - ) { - need_migration = true; - drop_reorder_reason = true; - responsible_captured_hir_ids.extend(diagnostics_info); + for captured_info in capture_disagnostic.iter() { + // Get the auto trait reasons of why migration is needed because of that capture, if there are any + let capture_trait_reasons = + if let Some(reasons) = auto_trait_diagnostic.get(captured_info) { + reasons.clone() + } else { + FxHashSet::default() + }; + + // Check if migration is needed because of drop reorder as a result of that capture + let capture_drop_reorder_reason = drop_reorder_diagnostic.contains(captured_info); + + // Combine all the reasons of why the root variable should be captured as a result of + // auto trait implementation issues + auto_trait_migration_reasons.extend(capture_trait_reasons.clone()); + + responsible_captured_hir_ids.insert(( + captured_info.0, + captured_info.1.clone(), + self.compute_2229_migrations_reasons( + capture_trait_reasons, + capture_drop_reorder_reason, + ), + )); } - if need_migration { + if capture_disagnostic.len() > 0 { need_migrations.push((var_hir_id, responsible_captured_hir_ids)); } } - ( need_migrations, - self.compute_2229_migrations_reasons(auto_trait_reasons, drop_reorder_reason), + self.compute_2229_migrations_reasons( + auto_trait_migration_reasons, + drop_migration_needed, + ), ) } @@ -1964,7 +1964,7 @@ fn should_do_rust_2021_incompatible_closure_captures_analysis( /// - s2: Comma separated names of the variables being migrated. fn migration_suggestion_for_2229( tcx: TyCtxt<'_>, - need_migrations: &Vec<(hir::HirId, FxHashSet<(Option, String)>)>, + need_migrations: &Vec, ) -> (String, String) { let need_migrations_variables = need_migrations.iter().map(|(v, _)| var_name(tcx, *v)).collect::>(); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed new file mode 100644 index 0000000000000..e5102fee58877 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed @@ -0,0 +1,138 @@ +// run-rustfix +#![deny(rust_2021_incompatible_closure_captures)] +//~^ NOTE: the lint level is defined here + +use std::thread; + +struct S(String); + +#[derive(Clone)] +struct T(i32); + +struct U(S, T); + +impl Clone for U { + fn clone(&self) -> Self { + U(S(String::from("Hello World")), T(0)) + } +} + +fn test_multi_issues() { + let f1 = U(S(String::from("foo")), T(0)); + let f2 = U(S(String::from("bar")), T(0)); + let c = || { let _ = (&f1, &f2); + //~^ ERROR: `Clone` trait implementation for closure, and drop order + //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f1.0` does not implement `Clone` + //~| NOTE: for more information, see + //~| HELP: add a dummy let to cause `f1`, `f2` to be fully captured + let _f_1 = f1.0; + //~^ NOTE: in Rust 2018, closure captures all of `f1`, but in Rust 2021, it only captures `f1.0` + let _f_2 = f2.1; + //~^ NOTE: in Rust 2018, closure captures all of `f2`, but in Rust 2021, it only captures `f2.1` + }; + + let c_clone = c.clone(); + + c_clone(); +} +//~^ NOTE: in Rust 2018, `f2` would be dropped here, but in Rust 2021, only `f2.1` would be dropped here alongside the closure + +fn test_capturing_all_disjoint_fields_individually() { + let f1 = U(S(String::from("foo")), T(0)); + let c = || { let _ = &f1; + //~^ ERROR: `Clone` trait implementation for closure + //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f1.0` does not implement `Clone` + //~| NOTE: for more information, see + //~| HELP: add a dummy let to cause `f1` to be fully captured + let _f_1 = f1.0; + //~^ NOTE: in Rust 2018, closure captures all of `f1`, but in Rust 2021, it only captures `f1.0` + let _f_2 = f1.1; + }; + + let c_clone = c.clone(); + + c_clone(); +} + +struct U1(S, T, S); + +impl Clone for U1 { + fn clone(&self) -> Self { + U1(S(String::from("foo")), T(0), S(String::from("bar"))) + } +} + +fn test_capturing_several_disjoint_fields_individually_1() { + let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar"))); + let c = || { let _ = &f1; + //~^ ERROR: `Clone` trait implementation for closure + //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f1.0` does not implement `Clone` + //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f1.2` does not implement `Clone` + //~| NOTE: for more information, see + //~| HELP: add a dummy let to cause `f1` to be fully captured + let _f_0 = f1.0; + //~^ NOTE: in Rust 2018, closure captures all of `f1`, but in Rust 2021, it only captures `f1.0` + let _f_2 = f1.2; + //~^ NOTE: in Rust 2018, closure captures all of `f1`, but in Rust 2021, it only captures `f1.2` + }; + + let c_clone = c.clone(); + + c_clone(); +} + +fn test_capturing_several_disjoint_fields_individually_2() { + let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar"))); + let c = || { let _ = &f1; + //~^ ERROR: `Clone` trait implementation for closure, and drop order + //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f1.0` does not implement `Clone` + //~| NOTE: for more information, see + //~| HELP: add a dummy let to cause `f1` to be fully captured + let _f_0 = f1.0; + //~^ NOTE: in Rust 2018, closure captures all of `f1`, but in Rust 2021, it only captures `f1.0` + let _f_1 = f1.1; + //~^ NOTE: in Rust 2018, closure captures all of `f1`, but in Rust 2021, it only captures `f1.1` + }; + + let c_clone = c.clone(); + + c_clone(); +} +//~^ NOTE: in Rust 2018, `f1` would be dropped here, but in Rust 2021, only `f1.1` would be dropped here alongside the closure +//~| NOTE: in Rust 2018, `f1` would be dropped here, but in Rust 2021, only `f1.0` would be dropped here alongside the closure + +struct SendPointer(*mut i32); +unsafe impl Send for SendPointer {} + +struct CustomInt(*mut i32); +struct SyncPointer(CustomInt); +unsafe impl Sync for SyncPointer {} +unsafe impl Send for CustomInt {} + +fn test_multi_traits_issues() { + let mut f1 = 10; + let f1 = CustomInt(&mut f1 as *mut i32); + let fptr1 = SyncPointer(f1); + + let mut f2 = 10; + let fptr2 = SendPointer(&mut f2 as *mut i32); + thread::spawn(move || { let _ = (&fptr1, &fptr2); unsafe { + //~^ ERROR: `Sync`, `Send` trait implementation for closure + //~| NOTE: in Rust 2018, this closure would implement `Sync`, `Send` as `fptr1` implements `Sync`, `Send`, but in Rust 2021, this closure would no longer implement `Sync`, `Send` as `fptr1.0.0` does not implement `Sync`, `Send` + //~| NOTE: in Rust 2018, this closure would implement `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure would no longer implement `Send` as `fptr2.0` does not implement `Send` + //~| NOTE: for more information, see + //~| HELP: add a dummy let to cause `fptr1`, `fptr2` to be fully captured + *fptr1.0.0 = 20; + //~^ NOTE: in Rust 2018, closure captures all of `fptr1`, but in Rust 2021, it only captures `fptr1.0.0` + *fptr2.0 = 20; + //~^ NOTE: in Rust 2018, closure captures all of `fptr2`, but in Rust 2021, it only captures `fptr2.0` + } }); +} + +fn main() { + test_multi_issues(); + test_capturing_all_disjoint_fields_individually(); + test_capturing_several_disjoint_fields_individually_1(); + test_capturing_several_disjoint_fields_individually_2(); + test_multi_traits_issues(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs new file mode 100644 index 0000000000000..d05c0bc1bbce9 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs @@ -0,0 +1,138 @@ +// run-rustfix +#![deny(rust_2021_incompatible_closure_captures)] +//~^ NOTE: the lint level is defined here + +use std::thread; + +struct S(String); + +#[derive(Clone)] +struct T(i32); + +struct U(S, T); + +impl Clone for U { + fn clone(&self) -> Self { + U(S(String::from("Hello World")), T(0)) + } +} + +fn test_multi_issues() { + let f1 = U(S(String::from("foo")), T(0)); + let f2 = U(S(String::from("bar")), T(0)); + let c = || { + //~^ ERROR: `Clone` trait implementation for closure, and drop order + //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f1.0` does not implement `Clone` + //~| NOTE: for more information, see + //~| HELP: add a dummy let to cause `f1`, `f2` to be fully captured + let _f_1 = f1.0; + //~^ NOTE: in Rust 2018, closure captures all of `f1`, but in Rust 2021, it only captures `f1.0` + let _f_2 = f2.1; + //~^ NOTE: in Rust 2018, closure captures all of `f2`, but in Rust 2021, it only captures `f2.1` + }; + + let c_clone = c.clone(); + + c_clone(); +} +//~^ NOTE: in Rust 2018, `f2` would be dropped here, but in Rust 2021, only `f2.1` would be dropped here alongside the closure + +fn test_capturing_all_disjoint_fields_individually() { + let f1 = U(S(String::from("foo")), T(0)); + let c = || { + //~^ ERROR: `Clone` trait implementation for closure + //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f1.0` does not implement `Clone` + //~| NOTE: for more information, see + //~| HELP: add a dummy let to cause `f1` to be fully captured + let _f_1 = f1.0; + //~^ NOTE: in Rust 2018, closure captures all of `f1`, but in Rust 2021, it only captures `f1.0` + let _f_2 = f1.1; + }; + + let c_clone = c.clone(); + + c_clone(); +} + +struct U1(S, T, S); + +impl Clone for U1 { + fn clone(&self) -> Self { + U1(S(String::from("foo")), T(0), S(String::from("bar"))) + } +} + +fn test_capturing_several_disjoint_fields_individually_1() { + let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar"))); + let c = || { + //~^ ERROR: `Clone` trait implementation for closure + //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f1.0` does not implement `Clone` + //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f1.2` does not implement `Clone` + //~| NOTE: for more information, see + //~| HELP: add a dummy let to cause `f1` to be fully captured + let _f_0 = f1.0; + //~^ NOTE: in Rust 2018, closure captures all of `f1`, but in Rust 2021, it only captures `f1.0` + let _f_2 = f1.2; + //~^ NOTE: in Rust 2018, closure captures all of `f1`, but in Rust 2021, it only captures `f1.2` + }; + + let c_clone = c.clone(); + + c_clone(); +} + +fn test_capturing_several_disjoint_fields_individually_2() { + let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar"))); + let c = || { + //~^ ERROR: `Clone` trait implementation for closure, and drop order + //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f1.0` does not implement `Clone` + //~| NOTE: for more information, see + //~| HELP: add a dummy let to cause `f1` to be fully captured + let _f_0 = f1.0; + //~^ NOTE: in Rust 2018, closure captures all of `f1`, but in Rust 2021, it only captures `f1.0` + let _f_1 = f1.1; + //~^ NOTE: in Rust 2018, closure captures all of `f1`, but in Rust 2021, it only captures `f1.1` + }; + + let c_clone = c.clone(); + + c_clone(); +} +//~^ NOTE: in Rust 2018, `f1` would be dropped here, but in Rust 2021, only `f1.1` would be dropped here alongside the closure +//~| NOTE: in Rust 2018, `f1` would be dropped here, but in Rust 2021, only `f1.0` would be dropped here alongside the closure + +struct SendPointer(*mut i32); +unsafe impl Send for SendPointer {} + +struct CustomInt(*mut i32); +struct SyncPointer(CustomInt); +unsafe impl Sync for SyncPointer {} +unsafe impl Send for CustomInt {} + +fn test_multi_traits_issues() { + let mut f1 = 10; + let f1 = CustomInt(&mut f1 as *mut i32); + let fptr1 = SyncPointer(f1); + + let mut f2 = 10; + let fptr2 = SendPointer(&mut f2 as *mut i32); + thread::spawn(move || unsafe { + //~^ ERROR: `Sync`, `Send` trait implementation for closure + //~| NOTE: in Rust 2018, this closure would implement `Sync`, `Send` as `fptr1` implements `Sync`, `Send`, but in Rust 2021, this closure would no longer implement `Sync`, `Send` as `fptr1.0.0` does not implement `Sync`, `Send` + //~| NOTE: in Rust 2018, this closure would implement `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure would no longer implement `Send` as `fptr2.0` does not implement `Send` + //~| NOTE: for more information, see + //~| HELP: add a dummy let to cause `fptr1`, `fptr2` to be fully captured + *fptr1.0.0 = 20; + //~^ NOTE: in Rust 2018, closure captures all of `fptr1`, but in Rust 2021, it only captures `fptr1.0.0` + *fptr2.0 = 20; + //~^ NOTE: in Rust 2018, closure captures all of `fptr2`, but in Rust 2021, it only captures `fptr2.0` + }); +} + +fn main() { + test_multi_issues(); + test_capturing_all_disjoint_fields_individually(); + test_capturing_several_disjoint_fields_individually_1(); + test_capturing_several_disjoint_fields_individually_2(); + test_multi_traits_issues(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr new file mode 100644 index 0000000000000..5f09230d45ca0 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr @@ -0,0 +1,134 @@ +error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure, and drop order + --> $DIR/multi_diagnostics.rs:23:13 + | +LL | let c = || { + | ^^ in Rust 2018, this closure would implement `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f1.0` does not implement `Clone` +... +LL | let _f_1 = f1.0; + | ---- in Rust 2018, closure captures all of `f1`, but in Rust 2021, it only captures `f1.0` +LL | +LL | let _f_2 = f2.1; + | ---- in Rust 2018, closure captures all of `f2`, but in Rust 2021, it only captures `f2.1` +... +LL | } + | - in Rust 2018, `f2` would be dropped here, but in Rust 2021, only `f2.1` would be dropped here alongside the closure + | +note: the lint level is defined here + --> $DIR/multi_diagnostics.rs:2:9 + | +LL | #![deny(rust_2021_incompatible_closure_captures)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: for more information, see +help: add a dummy let to cause `f1`, `f2` to be fully captured + | +LL | let c = || { let _ = (&f1, &f2); +LL | +LL | +LL | +LL | +LL | let _f_1 = f1.0; + ... + +error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure + --> $DIR/multi_diagnostics.rs:42:13 + | +LL | let c = || { + | ^^ in Rust 2018, this closure would implement `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f1.0` does not implement `Clone` +... +LL | let _f_1 = f1.0; + | ---- in Rust 2018, closure captures all of `f1`, but in Rust 2021, it only captures `f1.0` + | + = note: for more information, see +help: add a dummy let to cause `f1` to be fully captured + | +LL | let c = || { let _ = &f1; +LL | +LL | +LL | +LL | +LL | let _f_1 = f1.0; + ... + +error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure + --> $DIR/multi_diagnostics.rs:67:13 + | +LL | let c = || { + | ^^ + | | + | in Rust 2018, this closure would implement `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f1.0` does not implement `Clone` + | in Rust 2018, this closure would implement `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f1.2` does not implement `Clone` +... +LL | let _f_0 = f1.0; + | ---- in Rust 2018, closure captures all of `f1`, but in Rust 2021, it only captures `f1.0` +LL | +LL | let _f_2 = f1.2; + | ---- in Rust 2018, closure captures all of `f1`, but in Rust 2021, it only captures `f1.2` + | + = note: for more information, see +help: add a dummy let to cause `f1` to be fully captured + | +LL | let c = || { let _ = &f1; +LL | +LL | +LL | +LL | +LL | + ... + +error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure, and drop order + --> $DIR/multi_diagnostics.rs:86:13 + | +LL | let c = || { + | ^^ in Rust 2018, this closure would implement `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f1.0` does not implement `Clone` +... +LL | let _f_0 = f1.0; + | ---- in Rust 2018, closure captures all of `f1`, but in Rust 2021, it only captures `f1.0` +LL | +LL | let _f_1 = f1.1; + | ---- in Rust 2018, closure captures all of `f1`, but in Rust 2021, it only captures `f1.1` +... +LL | } + | - + | | + | in Rust 2018, `f1` would be dropped here, but in Rust 2021, only `f1.0` would be dropped here alongside the closure + | in Rust 2018, `f1` would be dropped here, but in Rust 2021, only `f1.1` would be dropped here alongside the closure + | + = note: for more information, see +help: add a dummy let to cause `f1` to be fully captured + | +LL | let c = || { let _ = &f1; +LL | +LL | +LL | +LL | +LL | let _f_0 = f1.0; + ... + +error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure + --> $DIR/multi_diagnostics.rs:119:19 + | +LL | thread::spawn(move || unsafe { + | ^^^^^^^^^^^^^^ + | | + | in Rust 2018, this closure would implement `Sync`, `Send` as `fptr1` implements `Sync`, `Send`, but in Rust 2021, this closure would no longer implement `Sync`, `Send` as `fptr1.0.0` does not implement `Sync`, `Send` + | in Rust 2018, this closure would implement `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure would no longer implement `Send` as `fptr2.0` does not implement `Send` +... +LL | *fptr1.0.0 = 20; + | ---------- in Rust 2018, closure captures all of `fptr1`, but in Rust 2021, it only captures `fptr1.0.0` +LL | +LL | *fptr2.0 = 20; + | -------- in Rust 2018, closure captures all of `fptr2`, but in Rust 2021, it only captures `fptr2.0` + | + = note: for more information, see +help: add a dummy let to cause `fptr1`, `fptr2` to be fully captured + | +LL | thread::spawn(move || { let _ = (&fptr1, &fptr2); unsafe { +LL | +LL | +LL | +LL | +LL | + ... + +error: aborting due to 5 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 ba5e5b573f1d6..226172fb93eb1 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/precise.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/precise.fixed @@ -1,6 +1,7 @@ // run-rustfix #![deny(rust_2021_incompatible_closure_captures)] +//~^ NOTE: the lint level is defined here #[derive(Debug)] struct Foo(i32); @@ -18,13 +19,16 @@ fn test_precise_analysis_drop_paths_not_captured_by_move() { let c = || { let _ = &t; //~^ ERROR: drop order + //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` let _t = &t.1; }; c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure struct S; impl Drop for S { @@ -40,14 +44,22 @@ fn test_precise_analysis_long_path_missing() { let c = || { let _ = &u; //~^ ERROR: drop order + //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `u` to be fully captured let _x = u.0.0; + //~^ NOTE: in Rust 2018, closure captures all of `u`, but in Rust 2021, it only captures `u.0.0` let _x = u.0.1; + //~^ NOTE: in Rust 2018, closure captures all of `u`, but in Rust 2021, it only captures `u.0.1` let _x = u.1.0; + //~^ NOTE: in Rust 2018, closure captures all of `u`, but in Rust 2021, it only captures `u.1.0` }; c(); } +//~^ NOTE: in Rust 2018, `u` would be dropped here, but in Rust 2021, only `u.0.0` would be dropped here alongside the closure +//~| NOTE: in Rust 2018, `u` would be dropped here, but in Rust 2021, only `u.0.1` would be dropped here alongside the closure +//~| NOTE: in Rust 2018, `u` would be dropped here, but in Rust 2021, only `u.1.0` would be dropped here alongside the closure + fn main() { test_precise_analysis_drop_paths_not_captured_by_move(); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/precise.rs b/src/test/ui/closures/2229_closure_analysis/migrations/precise.rs index 92b6f25c80dad..7035abe6de0a2 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/precise.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/precise.rs @@ -1,6 +1,7 @@ // run-rustfix #![deny(rust_2021_incompatible_closure_captures)] +//~^ NOTE: the lint level is defined here #[derive(Debug)] struct Foo(i32); @@ -18,13 +19,16 @@ fn test_precise_analysis_drop_paths_not_captured_by_move() { let c = || { //~^ ERROR: drop order + //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `t` to be fully captured let _t = t.0; + //~^ NOTE: in Rust 2018, closure captures all of `t`, but in Rust 2021, it only captures `t.0` let _t = &t.1; }; c(); } +//~^ NOTE: in Rust 2018, `t` would be dropped here, but in Rust 2021, only `t.0` would be dropped here alongside the closure struct S; impl Drop for S { @@ -40,14 +44,22 @@ fn test_precise_analysis_long_path_missing() { let c = || { //~^ ERROR: drop order + //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `u` to be fully captured let _x = u.0.0; + //~^ NOTE: in Rust 2018, closure captures all of `u`, but in Rust 2021, it only captures `u.0.0` let _x = u.0.1; + //~^ NOTE: in Rust 2018, closure captures all of `u`, but in Rust 2021, it only captures `u.0.1` let _x = u.1.0; + //~^ NOTE: in Rust 2018, closure captures all of `u`, but in Rust 2021, it only captures `u.1.0` }; c(); } +//~^ NOTE: in Rust 2018, `u` would be dropped here, but in Rust 2021, only `u.0.0` would be dropped here alongside the closure +//~| NOTE: in Rust 2018, `u` would be dropped here, but in Rust 2021, only `u.0.1` would be dropped here alongside the closure +//~| NOTE: in Rust 2018, `u` would be dropped here, but in Rust 2021, only `u.1.0` would be dropped here alongside the closure + fn main() { test_precise_analysis_drop_paths_not_captured_by_move(); 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 153c0d6b68671..ee2cae0ecb2a1 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/precise.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/precise.stderr @@ -1,5 +1,5 @@ error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/precise.rs:19:13 + --> $DIR/precise.rs:20:13 | LL | let c = || { | ^^ @@ -21,26 +21,32 @@ help: add a dummy let to cause `t` to be fully captured LL | let c = || { let _ = &t; LL | LL | +LL | LL | let _t = t.0; -LL | let _t = &t.1; -LL | }; - | +LL | + ... error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/precise.rs:41:13 + --> $DIR/precise.rs:45:13 | LL | let c = || { | ^^ ... LL | let _x = u.0.0; | ----- in Rust 2018, closure captures all of `u`, but in Rust 2021, it only captures `u.0.0` +LL | LL | let _x = u.0.1; | ----- in Rust 2018, closure captures all of `u`, but in Rust 2021, it only captures `u.0.1` +LL | LL | let _x = u.1.0; | ----- in Rust 2018, closure captures all of `u`, but in Rust 2021, it only captures `u.1.0` ... LL | } - | - in Rust 2018, `u` would be dropped here, but in Rust 2021, only `u.0.1`, `u.0.0`, `u.1.0` would be dropped here alongside the closure + | - + | | + | in Rust 2018, `u` would be dropped here, but in Rust 2021, only `u.0.1` would be dropped here alongside the closure + | in Rust 2018, `u` would be dropped here, but in Rust 2021, only `u.0.0` would be dropped here alongside the closure + | in Rust 2018, `u` would be dropped here, but in Rust 2021, only `u.1.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `u` to be fully captured @@ -48,9 +54,9 @@ help: add a dummy let to cause `u` to be fully captured LL | let c = || { let _ = &u; LL | LL | +LL | LL | let _x = u.0.0; -LL | let _x = u.0.1; -LL | let _x = u.1.0; +LL | ... error: aborting due to 2 previous errors From 8cbeaf738267c8ddb5ab205dae4404e2f25eeeeb Mon Sep 17 00:00:00 2001 From: Roxane Date: Fri, 9 Jul 2021 10:18:55 -0400 Subject: [PATCH 8/9] Address comments --- compiler/rustc_typeck/src/check/upvar.rs | 10 +++++----- .../2229_closure_analysis/migrations/auto_traits.fixed | 2 +- .../2229_closure_analysis/migrations/auto_traits.rs | 2 +- .../migrations/auto_traits.stderr | 2 +- .../migrations/multi_diagnostics.fixed | 4 ++-- .../migrations/multi_diagnostics.rs | 4 ++-- .../migrations/multi_diagnostics.stderr | 6 +++--- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 2b82b4dff2e5a..b6d1468b7a617 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -619,7 +619,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if auto_trait_reasons.len() > 0 && drop_reason { - reasons = format!("{}, and ", reasons); + reasons = format!("{} and ", reasons); } if drop_reason { @@ -886,12 +886,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Combine all the captures responsible for needing migrations into one HashSet - let mut capture_disagnostic = drop_reorder_diagnostic.clone(); + let mut capture_diagnostic = drop_reorder_diagnostic.clone(); for key in auto_trait_diagnostic.keys() { - capture_disagnostic.insert(key.clone()); + capture_diagnostic.insert(key.clone()); } - for captured_info in capture_disagnostic.iter() { + for captured_info in capture_diagnostic.iter() { // Get the auto trait reasons of why migration is needed because of that capture, if there are any let capture_trait_reasons = if let Some(reasons) = auto_trait_diagnostic.get(captured_info) { @@ -917,7 +917,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } - if capture_disagnostic.len() > 0 { + if capture_diagnostic.len() > 0 { need_migrations.push((var_hir_id, responsible_captured_hir_ids)); } } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed index 42863b440fc1d..e2b7b8f027520 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed @@ -56,7 +56,7 @@ impl Clone for U { fn test_clone_trait() { let f = U(S(String::from("Hello World")), T(0)); let c = || { let _ = &f; - //~^ ERROR: `Clone` trait implementation for closure, and drop order + //~^ ERROR: `Clone` trait implementation for closure and drop order //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f.1` does not implement `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs index ae987f526d044..6c56ca27475a3 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs @@ -56,7 +56,7 @@ impl Clone for U { fn test_clone_trait() { let f = U(S(String::from("Hello World")), T(0)); let c = || { - //~^ ERROR: `Clone` trait implementation for closure, and drop order + //~^ ERROR: `Clone` trait implementation for closure and drop order //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f.1` does not implement `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr index 2af85852c01a0..9c954b1465d83 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr @@ -43,7 +43,7 @@ LL | LL | *fptr.0.0 = 20; ... -error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure, and drop order +error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order --> $DIR/auto_traits.rs:58:13 | LL | let c = || { diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed index e5102fee58877..98f578abc44dc 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed @@ -21,7 +21,7 @@ fn test_multi_issues() { let f1 = U(S(String::from("foo")), T(0)); let f2 = U(S(String::from("bar")), T(0)); let c = || { let _ = (&f1, &f2); - //~^ ERROR: `Clone` trait implementation for closure, and drop order + //~^ ERROR: `Clone` trait implementation for closure and drop order //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f1.0` does not implement `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1`, `f2` to be fully captured @@ -84,7 +84,7 @@ fn test_capturing_several_disjoint_fields_individually_1() { fn test_capturing_several_disjoint_fields_individually_2() { let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar"))); let c = || { let _ = &f1; - //~^ ERROR: `Clone` trait implementation for closure, and drop order + //~^ ERROR: `Clone` trait implementation for closure and drop order //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f1.0` does not implement `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1` to be fully captured diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs index d05c0bc1bbce9..1577b91c96018 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs @@ -21,7 +21,7 @@ fn test_multi_issues() { let f1 = U(S(String::from("foo")), T(0)); let f2 = U(S(String::from("bar")), T(0)); let c = || { - //~^ ERROR: `Clone` trait implementation for closure, and drop order + //~^ ERROR: `Clone` trait implementation for closure and drop order //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f1.0` does not implement `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1`, `f2` to be fully captured @@ -84,7 +84,7 @@ fn test_capturing_several_disjoint_fields_individually_1() { fn test_capturing_several_disjoint_fields_individually_2() { let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar"))); let c = || { - //~^ ERROR: `Clone` trait implementation for closure, and drop order + //~^ ERROR: `Clone` trait implementation for closure and drop order //~| NOTE: in Rust 2018, this closure would implement `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure would no longer implement `Clone` as `f1.0` does not implement `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1` to be fully captured diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr index 5f09230d45ca0..856fbdf5f9fd0 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr @@ -1,4 +1,4 @@ -error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure, and drop order +error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order --> $DIR/multi_diagnostics.rs:23:13 | LL | let c = || { @@ -75,7 +75,7 @@ LL | LL | ... -error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure, and drop order +error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order --> $DIR/multi_diagnostics.rs:86:13 | LL | let c = || { @@ -90,8 +90,8 @@ LL | let _f_1 = f1.1; LL | } | - | | - | in Rust 2018, `f1` would be dropped here, but in Rust 2021, only `f1.0` would be dropped here alongside the closure | in Rust 2018, `f1` would be dropped here, but in Rust 2021, only `f1.1` would be dropped here alongside the closure + | in Rust 2018, `f1` would be dropped here, but in Rust 2021, only `f1.0` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `f1` to be fully captured From 08c616741c6eff64443cc50d2ec8db9663ff61d8 Mon Sep 17 00:00:00 2001 From: Roxane Date: Fri, 9 Jul 2021 13:32:30 -0400 Subject: [PATCH 9/9] Ensure deterministic ordering for diagnostics --- compiler/rustc_typeck/src/check/upvar.rs | 8 +++++--- .../migrations/multi_diagnostics.stderr | 2 +- .../2229_closure_analysis/migrations/precise.stderr | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index b6d1468b7a617..c42ca936e9758 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -96,7 +96,7 @@ type MigrationNeededForCapture = (Option, String, String); /// Intermediate format to store the hir id of the root variable and a HashSet containing /// information on why the root variable should be fully captured -type MigrationDiagnosticInfo = (hir::HirId, FxHashSet); +type MigrationDiagnosticInfo = (hir::HirId, Vec); struct InferBorrowKindVisitor<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, @@ -861,7 +861,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Perform auto-trait analysis for (&var_hir_id, _) in upvars.iter() { - let mut responsible_captured_hir_ids = FxHashSet::default(); + let mut responsible_captured_hir_ids = Vec::new(); let auto_trait_diagnostic = if let Some(diagnostics_info) = self.compute_2229_migrations_for_trait(min_captures, var_hir_id, closure_clause) @@ -891,6 +891,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { capture_diagnostic.insert(key.clone()); } + let mut capture_diagnostic = capture_diagnostic.into_iter().collect::>(); + capture_diagnostic.sort(); for captured_info in capture_diagnostic.iter() { // Get the auto trait reasons of why migration is needed because of that capture, if there are any let capture_trait_reasons = @@ -907,7 +909,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // auto trait implementation issues auto_trait_migration_reasons.extend(capture_trait_reasons.clone()); - responsible_captured_hir_ids.insert(( + responsible_captured_hir_ids.push(( captured_info.0, captured_info.1.clone(), self.compute_2229_migrations_reasons( diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr index 856fbdf5f9fd0..8a42683c1df9f 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr @@ -90,8 +90,8 @@ LL | let _f_1 = f1.1; LL | } | - | | - | in Rust 2018, `f1` would be dropped here, but in Rust 2021, only `f1.1` would be dropped here alongside the closure | in Rust 2018, `f1` would be dropped here, but in Rust 2021, only `f1.0` would be dropped here alongside the closure + | in Rust 2018, `f1` would be dropped here, but in Rust 2021, only `f1.1` would be dropped here alongside the closure | = note: for more information, see help: add a dummy let to cause `f1` to be fully captured 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 ee2cae0ecb2a1..5bf73ccc55400 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/precise.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/precise.stderr @@ -44,8 +44,8 @@ LL | let _x = u.1.0; LL | } | - | | - | in Rust 2018, `u` would be dropped here, but in Rust 2021, only `u.0.1` would be dropped here alongside the closure | in Rust 2018, `u` would be dropped here, but in Rust 2021, only `u.0.0` would be dropped here alongside the closure + | in Rust 2018, `u` would be dropped here, but in Rust 2021, only `u.0.1` would be dropped here alongside the closure | in Rust 2018, `u` would be dropped here, but in Rust 2021, only `u.1.0` would be dropped here alongside the closure | = note: for more information, see