diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 4d6d1da194fc6..c42ca936e9758 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, Vec); + struct InferBorrowKindVisitor<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, } @@ -498,18 +515,58 @@ 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!( - "{} will change in Rust 2021", + "changes to closure capture in Rust 2021 will affect {}", reasons ) .as_str(), ); + for (var_hir_id, diagnostics_info) in need_migrations.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, + )); + } + + // 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_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]; + + 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 "); let closure_body_span = self.tcx.hir().span(body_id.hir_id); let (sugg, app) = @@ -556,13 +613,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if auto_trait_reasons.len() > 0 { reasons = format!( - "{} trait implementation", + "{} trait implementation for closure", auto_trait_reasons.clone().into_iter().collect::>().join(", ") ); } if auto_trait_reasons.len() > 0 && drop_reason { - reasons = format!("{}, and ", reasons); + reasons = format!("{} and ", reasons); } if drop_reason { @@ -572,20 +629,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { reasons } - /// Returns true if migration is needed for trait for the provided var_hir_id - 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, - ) -> bool { + ) -> 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)) { root_var_min_capture_list } else { - return false; + return None; }; let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id)); @@ -604,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( @@ -625,106 +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 true; + // 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), + ); } - } - false - } - - /// 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. - /// - /// 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. - fn compute_2229_migrations_for_trait( - &self, - min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, - var_hir_id: hir::HirId, - closure_clause: hir::CaptureBy, - ) -> Option> { - let tcx = self.infcx.tcx; - - // Check whether catpured fields also implement the trait - let mut auto_trait_reasons = FxHashSet::default(); - - if self.need_2229_migrations_for_trait( - min_captures, - var_hir_id, - tcx.lang_items().clone_trait(), - closure_clause, - ) { - auto_trait_reasons.insert("`Clone`"); - } - - if self.need_2229_migrations_for_trait( - min_captures, - var_hir_id, - tcx.lang_items().sync_trait(), - closure_clause, - ) { - auto_trait_reasons.insert("`Sync`"); - } - if 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`"); - } + let mut capture_problems = FxHashSet::default(); - if self.need_2229_migrations_for_trait( - min_captures, - var_hir_id, - tcx.lang_items().unpin_trait(), - closure_clause, - ) { - auto_trait_reasons.insert("`Unpin`"); - } - - if 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`"); - } + // 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 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`"); + 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); + 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 @@ -737,8 +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 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 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, @@ -746,11 +765,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, closure_clause: hir::CaptureBy, var_hir_id: hir::HirId, - ) -> bool { + ) -> 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())) { - return false; + return None; } let root_var_min_capture_list = if let Some(root_var_min_capture_list) = @@ -763,21 +782,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 +820,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 @@ -812,15 +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 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 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, String) { + ) -> (Vec, String) { let upvars = if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { upvars } else { @@ -828,38 +856,79 @@ 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; - if let Some(trait_migration_cause) = + 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) { - need_migration = true; - auto_trait_reasons.extend(trait_migration_cause); + 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_diagnostic = drop_reorder_diagnostic.clone(); + for key in auto_trait_diagnostic.keys() { + capture_diagnostic.insert(key.clone()); } - if 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; + 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 = + 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.push(( + captured_info.0, + captured_info.1.clone(), + self.compute_2229_migrations_reasons( + capture_trait_reasons, + capture_drop_reorder_reason, + ), + )); } - if need_migration { - need_migrations.push(var_hir_id); + if capture_diagnostic.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, + ), ) } @@ -1320,6 +1389,26 @@ 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); + let owner_span = match owner_node { + hir::Node::Item(item) => match item.kind { + 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) => 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> { fcx: &'a FnCtxt<'a, 'tcx>, @@ -1877,10 +1966,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, ) -> (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.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed index 134d07c400b3a..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 @@ -1,5 +1,6 @@ // run-rustfix #![deny(rust_2021_incompatible_closure_captures)] +//~^ NOTE: the lint level is defined here use std::thread; @@ -11,9 +12,12 @@ 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` 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; + //~^ NOTE: in Rust 2018, closure captures all of `fptr`, but in Rust 2021, it only captures `fptr.0` } }); } @@ -28,9 +32,12 @@ 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` 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; + //~^ NOTE: in Rust 2018, closure captures all of `fptr`, but in Rust 2021, it only captures `fptr.0.0` } }); } @@ -49,9 +56,12 @@ 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` 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; + //~^ NOTE: in Rust 2018, closure captures all of `f`, but in Rust 2021, it only captures `f.1` println!("{:?}", f_1.0); }; @@ -59,6 +69,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 b48a724f052f0..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 @@ -1,5 +1,6 @@ // run-rustfix #![deny(rust_2021_incompatible_closure_captures)] +//~^ NOTE: the lint level is defined here use std::thread; @@ -11,9 +12,12 @@ 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` 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; + //~^ NOTE: in Rust 2018, closure captures all of `fptr`, but in Rust 2021, it only captures `fptr.0` }); } @@ -28,9 +32,12 @@ 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` 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; + //~^ NOTE: in Rust 2018, closure captures all of `fptr`, but in Rust 2021, it only captures `fptr.0.0` }); } @@ -49,9 +56,12 @@ 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` 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; + //~^ NOTE: in Rust 2018, closure captures all of `f`, but in Rust 2021, it only captures `f.1` println!("{:?}", f_1.0); }; @@ -59,6 +69,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 3d3dde15412bf..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 @@ -1,13 +1,11 @@ -error: `Send` trait implementation will change in Rust 2021 - --> $DIR/auto_traits.rs:13:19 +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 { - | ___________________^ -LL | | -LL | | -LL | | *fptr.0 = 20; -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 @@ -20,20 +18,19 @@ help: add a dummy let to cause `fptr` to be fully captured LL | thread::spawn(move || { let _ = &fptr; unsafe { LL | LL | +LL | +LL | LL | *fptr.0 = 20; -LL | } }); - | + ... -error: `Sync`, `Send` trait implementation will change in Rust 2021 - --> $DIR/auto_traits.rs:30:19 +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 { - | ___________________^ -LL | | -LL | | -LL | | *fptr.0.0 = 20; -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 @@ -41,21 +38,22 @@ help: add a dummy let to cause `fptr` to be fully captured LL | thread::spawn(move || { let _ = &fptr; unsafe { LL | LL | +LL | +LL | LL | *fptr.0.0 = 20; -LL | } }); - | + ... -error: `Clone` trait implementation, and drop order will change in Rust 2021 - --> $DIR/auto_traits.rs:51:13 +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 = || { - | _____________^ -LL | | -LL | | -LL | | let f_1 = f.1; -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 | = note: for more information, see help: add a dummy let to cause `f` to be fully captured @@ -63,10 +61,10 @@ help: add a dummy let to cause `f` to be fully captured LL | let c = || { let _ = &f; LL | LL | +LL | +LL | LL | let f_1 = f.1; -LL | println!("{:?}", f_1.0); -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 51d9c4881af3f..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 @@ -18,12 +18,18 @@ 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(); } +//~^ 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 @@ -37,12 +43,16 @@ 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; }; 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. @@ -54,11 +64,13 @@ 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); }; 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. @@ -73,11 +85,13 @@ 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; }; 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); @@ -92,11 +106,13 @@ 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; }; 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. @@ -108,10 +124,14 @@ 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(); } +//~^ 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, @@ -124,10 +144,12 @@ 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(); } +//~^ 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 c732cbb4fa51e..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 @@ -18,12 +18,18 @@ 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(); } +//~^ 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 @@ -37,12 +43,16 @@ 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; }; 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. @@ -54,11 +64,13 @@ 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); }; 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. @@ -73,11 +85,13 @@ 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; }; 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); @@ -92,11 +106,13 @@ 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; }; 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. @@ -108,10 +124,14 @@ 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(); } +//~^ 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, @@ -124,10 +144,12 @@ 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(); } +//~^ 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 89a2b0eb95366..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,15 +1,24 @@ -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 = || { - | _____________^ -LL | | -LL | | -LL | | -... | -LL | | let _t2 = t2.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 | +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 @@ -27,18 +36,23 @@ LL | LL | let _t = t.0; ... -error: drop order will change in Rust 2021 - --> $DIR/insignificant_drop.rs:35:13 - | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -... | -LL | | let _t2 = t2; -LL | | }; - | |_____^ +error: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/insignificant_drop.rs:41:13 + | +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 | +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 @@ -48,21 +62,20 @@ 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 - | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.0; -LL | | println!("{}", t1.1); -LL | | }; - | |_____^ +error: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/insignificant_drop.rs:62:13 + | +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 | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -72,21 +85,20 @@ 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 - | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.0; -LL | | let _t1 = t1.0; -LL | | }; - | |_____^ +error: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/insignificant_drop.rs:83:13 + | +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 | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -96,21 +108,20 @@ 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 - | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.0; -LL | | let _s = s.0; -LL | | }; - | |_____^ +error: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/insignificant_drop.rs:104:13 + | +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 | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -120,20 +131,25 @@ 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 - | -LL | let c = move || { - | _____________^ -LL | | -LL | | -LL | | -LL | | println!("{} {}", t1.1, t.1); -LL | | }; - | |_____^ +error: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/insignificant_drop.rs:122:13 + | +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 | = note: for more information, see help: add a dummy let to cause `t1`, `t` to be fully captured @@ -143,20 +159,20 @@ 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 +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; -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 | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -166,8 +182,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..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 @@ -39,10 +39,12 @@ 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(); } +//~^ 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 @@ -57,10 +59,12 @@ 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(); } +//~^ 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 17cee28e31117..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 @@ -39,10 +39,12 @@ 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(); } +//~^ 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 @@ -57,10 +59,12 @@ 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(); } +//~^ 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 1d3bda03d0e16..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,14 +1,14 @@ -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 = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.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 | note: the lint level is defined here --> $DIR/insignificant_drop_attr_migrations.rs:3:9 @@ -23,20 +23,20 @@ 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 +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; -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 | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -46,8 +46,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..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 @@ -21,20 +21,24 @@ 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(); } +//~^ 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)); 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 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 dd9556aa56784..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 @@ -21,20 +21,24 @@ 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(); } +//~^ 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)); 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 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 2d5e5e5e55c14..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,14 +1,14 @@ -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 = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.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 | note: the lint level is defined here --> $DIR/migrations_rustfix.rs:2:9 @@ -23,14 +23,19 @@ LL | LL | LL | LL | let _t = t.0; -LL | }; - | +LL | + ... -error: drop order will change in Rust 2021 - --> $DIR/migrations_rustfix.rs:31:13 +error: changes to closure capture in Rust 2021 will affect drop order + --> $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` +... +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 7f49b460ef63a..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 @@ -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)] @@ -17,9 +18,12 @@ where { let f = panic::AssertUnwindSafe(f); let result = panic::catch_unwind(move || { let _ = &f; - //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` trait implementation + //~^ 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() + //~^ 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 3c654bec52605..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 @@ -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)] @@ -17,9 +18,12 @@ where { let f = panic::AssertUnwindSafe(f); let result = panic::catch_unwind(move || { - //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` trait implementation + //~^ 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() + //~^ 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 dca5c454b83be..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,13 +1,11 @@ -error: `UnwindSafe`, `RefUnwindSafe` trait implementation will change in Rust 2021 - --> $DIR/mir_calls_to_shims.rs:19:38 +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 || { - | ______________________________________^ -LL | | -LL | | -LL | | f.0() -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 @@ -20,9 +18,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 | LL | f.0() -LL | }); - | + ... error: aborting due to previous error 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..98f578abc44dc --- /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..1577b91c96018 --- /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..8a42683c1df9f --- /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 2788207296f11..5bf73ccc55400 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/precise.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/precise.stderr @@ -1,14 +1,14 @@ -error: drop order will change in Rust 2021 - --> $DIR/precise.rs:19:13 +error: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/precise.rs:20:13 | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | let _t = t.0; -LL | | let _t = &t.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 | note: the lint level is defined here --> $DIR/precise.rs:3:9 @@ -21,23 +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: drop order will change in Rust 2021 - --> $DIR/precise.rs:41:13 +error: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/precise.rs:45:13 | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | let _x = u.0.0; -LL | | let _x = u.0.1; -LL | | let _x = 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 | +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.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 help: add a dummy let to cause `u` to be fully captured @@ -45,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 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..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 @@ -27,12 +27,18 @@ 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(); } +//~^ 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 @@ -46,12 +52,16 @@ 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; }; 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. @@ -63,11 +73,13 @@ 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); }; 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. @@ -81,10 +93,12 @@ 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(); } +//~^ 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, @@ -97,10 +111,12 @@ 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(); } +//~^ 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() { @@ -111,10 +127,12 @@ 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(); } +//~^ 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. @@ -127,10 +145,53 @@ 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(); } +//~^ 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(); @@ -140,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 0890fc1c21256..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 @@ -27,12 +27,18 @@ 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(); } +//~^ 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 @@ -46,12 +52,16 @@ 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; }; 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. @@ -63,11 +73,13 @@ 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); }; 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. @@ -81,10 +93,12 @@ 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(); } +//~^ 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, @@ -97,10 +111,12 @@ 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(); } +//~^ 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() { @@ -111,10 +127,12 @@ 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(); } +//~^ 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. @@ -127,10 +145,53 @@ 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(); } +//~^ 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(); @@ -140,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 ebf9f169fd400..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,15 +1,24 @@ -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 = || { - | _____________^ -LL | | -LL | | -LL | | -... | -LL | | let _t2 = t2.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 | +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 @@ -24,21 +33,26 @@ 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 - | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -... | -LL | | let _t2 = t2; -LL | | }; - | |_____^ +error: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/significant_drop.rs:50:13 + | +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 | +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 @@ -48,21 +62,20 @@ 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 - | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.0; -LL | | println!("{:?}", t1.1); -LL | | }; - | |_____^ +error: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/significant_drop.rs:71:13 + | +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 | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -72,20 +85,20 @@ 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 - | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.0; -LL | | }; - | |_____^ +error: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/significant_drop.rs:91:13 + | +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 | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -95,20 +108,20 @@ LL | LL | LL | LL | let _t = t.0; -LL | }; - | +LL | + ... -error: drop order will change in Rust 2021 - --> $DIR/significant_drop.rs:95:13 - | -LL | let c = || { - | _____________^ -LL | | -LL | | -LL | | -LL | | let _t = t.0; -LL | | }; - | |_____^ +error: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/significant_drop.rs:109:13 + | +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 | = note: for more information, see help: add a dummy let to cause `t` to be fully captured @@ -118,20 +131,20 @@ LL | LL | LL | LL | let _t = t.0; -LL | }; - | +LL | + ... -error: drop order will change in Rust 2021 - --> $DIR/significant_drop.rs:109:13 +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; -LL | | }; - | |_____^ +LL | let c = || { + | ^^ +... +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 @@ -141,20 +154,25 @@ LL | LL | LL | LL | let _t = t.1; -LL | }; - | +LL | + ... -error: drop order will change in Rust 2021 - --> $DIR/significant_drop.rs:125:13 +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); -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 | = note: for more information, see help: add a dummy let to cause `t1`, `t` to be fully captured @@ -164,8 +182,54 @@ LL | LL | LL | LL | println!("{:?} {:?}", t1.1, t.1); +LL | + ... + +error: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/significant_drop.rs:163:21 + | +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 + | + = 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 | 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 | + = 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 7 previous errors +error: aborting due to 9 previous errors