From 9c84ac86d1325816c25531e95777adf467cf31e4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 4 Nov 2021 12:50:24 -0400 Subject: [PATCH 1/4] introduce an enum for tracking the 2229 migration causes --- compiler/rustc_typeck/src/check/upvar.rs | 58 ++++++++++++++++++------ 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 9c7b0b2cacb06..7da0838e07a9b 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -86,7 +86,10 @@ 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); +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +enum CapturesInfo { + CapturingLess { source_expr: Option, var_name: 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 @@ -963,7 +966,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !capture_problems.is_empty() { problematic_captures.insert( - (capture.info.path_expr_id, capture.to_string(self.tcx)), + CapturesInfo::CapturingLess { + source_expr: capture.info.path_expr_id, + var_name: capture.to_string(self.tcx), + }, capture_problems, ); } @@ -986,6 +992,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// This function only returns a HashSet of CapturesInfo for significant drops. If there /// are no significant drops than None is returned + #[instrument(level = "debug", skip(self))] fn compute_2229_migrations_for_drop( &self, closure_def_id: DefId, @@ -997,12 +1004,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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())) { + debug!("does not have significant drop"); return None; } let Some(root_var_min_capture_list) = min_captures.and_then(|m| m.get(&var_hir_id)) else { // The upvar is mentioned within the closure but no path starting from it is - // used. + // used. This occurs when you have (e.g.) + // + // ``` + // let x = move || { + // let _ = y; + // }); + // ``` + debug!("no path starting from it is used"); + match closure_clause { // Only migrate if closure is a move closure @@ -1012,6 +1028,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; }; + debug!(?root_var_min_capture_list); let mut projections_list = Vec::new(); let mut diagnostics_info = FxHashSet::default(); @@ -1021,19 +1038,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Only care about captures that are moved into the closure 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), - )); + diagnostics_info.insert(CapturesInfo::CapturingLess { + source_expr: captured_place.info.path_expr_id, + var_name: captured_place.to_string(self.tcx), + }); } ty::UpvarCapture::ByRef(..) => {} } } + debug!(?projections_list); + debug!(?diagnostics_info); + let is_moved = !projections_list.is_empty(); + debug!(?is_moved); let is_not_completely_captured = root_var_min_capture_list.iter().any(|capture| !capture.place.projections.is_empty()); + debug!(?is_not_completely_captured); if is_moved && is_not_completely_captured @@ -1066,6 +1088,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// 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 + #[instrument(level = "debug", skip(self))] fn compute_2229_migrations( &self, closure_def_id: DefId, @@ -1131,14 +1154,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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, - ), - )); + match captured_info { + CapturesInfo::CapturingLess { source_expr, var_name } => { + responsible_captured_hir_ids.push(( + *source_expr, + var_name.clone(), + self.compute_2229_migrations_reasons( + capture_trait_reasons, + capture_drop_reorder_reason, + ), + )); + } + } } if !capture_diagnostic.is_empty() { @@ -2087,6 +2114,7 @@ fn var_name(tcx: TyCtxt<'_>, var_hir_id: hir::HirId) -> Symbol { tcx.hir().name(var_hir_id) } +#[instrument(level = "debug", skip(tcx))] fn should_do_rust_2021_incompatible_closure_captures_analysis( tcx: TyCtxt<'_>, closure_id: hir::HirId, From 76bc02715e3495f66860e1d470d224d2607336a6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 4 Nov 2021 17:44:29 -0400 Subject: [PATCH 2/4] rework diagnostic reporting to be more structured --- compiler/rustc_typeck/src/check/upvar.rs | 185 ++++++++++-------- .../migrations/auto_traits.fixed | 9 +- .../migrations/auto_traits.rs | 9 +- .../migrations/auto_traits.stderr | 15 +- .../migrations/mir_calls_to_shims.fixed | 5 +- .../migrations/mir_calls_to_shims.rs | 5 +- .../migrations/mir_calls_to_shims.stderr | 7 +- .../migrations/multi_diagnostics.fixed | 14 +- .../migrations/multi_diagnostics.rs | 14 +- .../migrations/multi_diagnostics.stderr | 23 +-- 10 files changed, 164 insertions(+), 122 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 7da0838e07a9b..ef618ff51edc0 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -88,19 +88,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// name (i.e: a.b.c) #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] enum CapturesInfo { + /// We previously captured all of `x`, but now we capture some sub-path. CapturingLess { source_expr: Option, var_name: String }, + //CapturingNothing { + // // where the variable appears in the closure (but is not captured) + // use_span: Span, + //}, } -/// 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); +/// Reasons that we might issue a migration warning. +#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +struct MigrationWarningReason { + /// When we used to capture `x` in its entirety, we implemented the auto-trait(s) + /// in this vec, but now we don't. + auto_traits: Vec<&'static str>, + + /// When we used to capture `x` in its entirety, we would execute some destructors + /// at a different time. + drop_order: bool, +} + +impl MigrationWarningReason { + fn migration_message(&self) -> String { + let base = "changes to closure capture in Rust 2021 will affect"; + if !self.auto_traits.is_empty() && self.drop_order { + format!("{} drop order and which traits the closure implements", base) + } else if self.drop_order { + format!("{} drop order", base) + } else { + format!("{} which traits the closure implements", base) + } + } +} + +/// Intermediate format to store information needed to generate a note in the migration lint. +struct MigrationLintNote { + captures_info: CapturesInfo, + + /// reasons why migration is needed for this capture + reason: MigrationWarningReason, +} /// 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 NeededMigration { + var_hir_id: hir::HirId, + diagnostics_info: Vec, +} struct InferBorrowKindVisitor<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, @@ -710,47 +744,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { closure_head_span, |lint| { let mut diagnostics_builder = lint.build( - format!( - "changes to closure capture in Rust 2021 will affect {}", - reasons - ) - .as_str(), + &reasons.migration_message(), ); - for (var_hir_id, diagnostics_info) in need_migrations.iter() { + for NeededMigration { var_hir_id, diagnostics_info } in &need_migrations { // 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, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`", - self.tcx.hir().name(*var_hir_id), - captured_name, - )); + for lint_note in diagnostics_info.iter() { + match &lint_note.captures_info { + CapturesInfo::CapturingLess { source_expr: Some(capture_expr_id), var_name: captured_name } => { + let cause_span = self.tcx.hir().span(*capture_expr_id); + diagnostics_builder.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`", + 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") { + if lint_note.reason.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, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure", - self.tcx.hir().name(*var_hir_id), - captured_name, - )); + match &lint_note.captures_info { + CapturesInfo::CapturingLess { var_name: captured_name, .. } => { + diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of 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 implements {} as `{}` implements {}, but in Rust 2021, this closure will no longer implement {} as `{}` does not implement {}", - missing_trait, - self.tcx.hir().name(*var_hir_id), - missing_trait, - missing_trait, - captured_name, - missing_trait, - )); + for &missing_trait in &lint_note.reason.auto_traits { + // not capturing something anymore cannot cause a trait to fail to be implemented: + match &lint_note.captures_info { + CapturesInfo::CapturingLess { var_name: captured_name, .. } => { + diagnostics_builder.span_label(closure_head_span, format!("in Rust 2018, this closure implements {missing_trait} as `{x}` implements {missing_trait}, but in Rust 2021, this closure will no longer implement {missing_trait} as `{p}` does not implement {missing_trait}", + missing_trait = missing_trait, + x = self.tcx.hir().name(*var_hir_id), + p = captured_name, + )); + } + } } } } @@ -843,25 +880,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Combines all the reasons for 2229 migrations fn compute_2229_migrations_reasons( &self, - auto_trait_reasons: FxHashSet<&str>, - drop_reason: bool, - ) -> String { - let mut reasons = String::new(); - - if !auto_trait_reasons.is_empty() { - reasons = format!( - "{} trait implementation for closure", - auto_trait_reasons.clone().into_iter().collect::>().join(", ") - ); - } + auto_trait_reasons: FxHashSet<&'static str>, + drop_order: bool, + ) -> MigrationWarningReason { + let mut reasons = MigrationWarningReason::default(); - if !auto_trait_reasons.is_empty() && drop_reason { - reasons = format!("{} and ", reasons); + for auto_trait in auto_trait_reasons { + reasons.auto_traits.push(auto_trait); } - if drop_reason { - reasons = format!("{}drop order", reasons); - } + reasons.drop_order = drop_order; reasons } @@ -877,7 +905,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, var_hir_id: hir::HirId, closure_clause: hir::CaptureBy, - ) -> Option>> { + ) -> Option>> { let auto_traits_def_id = vec![ self.tcx.lang_items().clone_trait(), self.tcx.lang_items().sync_trait(), @@ -1022,7 +1050,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match closure_clause { // Only migrate if closure is a move closure - hir::CaptureBy::Value => return Some(FxHashSet::default()), + hir::CaptureBy::Value => { + let diagnostics_info = FxHashSet::default(); + //diagnostics_info.insert(CapturesInfo::CapturingNothing); + //let upvars = self.tcx.upvars_mentioned(closure_def_id).expect("must be an upvar"); + //let _span = upvars[&var_hir_id]; + return Some(diagnostics_info); + } hir::CaptureBy::Ref => {} } @@ -1095,9 +1129,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { closure_span: Span, closure_clause: hir::CaptureBy, min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, - ) -> (Vec, String) { + ) -> (Vec, MigrationWarningReason) { let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) else { - return (Vec::new(), String::new()); + return (Vec::new(), MigrationWarningReason::default()); }; let mut need_migrations = Vec::new(); @@ -1106,7 +1140,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Perform auto-trait analysis for (&var_hir_id, _) in upvars.iter() { - let mut responsible_captured_hir_ids = Vec::new(); + let mut diagnostics_info = Vec::new(); let auto_trait_diagnostic = if let Some(diagnostics_info) = self.compute_2229_migrations_for_trait(min_captures, var_hir_id, closure_clause) @@ -1138,38 +1172,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut capture_diagnostic = capture_diagnostic.into_iter().collect::>(); capture_diagnostic.sort(); - for captured_info in capture_diagnostic.iter() { + for captures_info in capture_diagnostic { // 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) { + if let Some(reasons) = auto_trait_diagnostic.get(&captures_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); + let capture_drop_reorder_reason = drop_reorder_diagnostic.contains(&captures_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()); - match captured_info { - CapturesInfo::CapturingLess { source_expr, var_name } => { - responsible_captured_hir_ids.push(( - *source_expr, - var_name.clone(), - self.compute_2229_migrations_reasons( - capture_trait_reasons, - capture_drop_reorder_reason, - ), - )); - } - } + diagnostics_info.push(MigrationLintNote { + captures_info, + reason: self.compute_2229_migrations_reasons( + capture_trait_reasons, + capture_drop_reorder_reason, + ), + }); } - if !capture_diagnostic.is_empty() { - need_migrations.push((var_hir_id, responsible_captured_hir_ids)); + if !diagnostics_info.is_empty() { + need_migrations.push(NeededMigration { var_hir_id, diagnostics_info }); } } ( @@ -2130,10 +2159,12 @@ 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::>(); + let need_migrations_variables = need_migrations + .iter() + .map(|NeededMigration { var_hir_id: 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 b0fc5120f08f2..b938b8429537e 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 @@ -20,7 +20,7 @@ fn test_send_trait() { let mut f = 10; let fptr = SendPointer(&mut f as *mut i32); thread::spawn(move || { let _ = &fptr; unsafe { - //~^ ERROR: `Send` trait implementation for closure + //~^ ERROR: changes to closure capture //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured @@ -40,8 +40,9 @@ 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 for closure - //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send` + //~^ ERROR: changes to closure capture + //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` as `fptr.0.0` does not implement `Sync` + //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0.0` does not implement `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0.0 = 20; @@ -65,7 +66,7 @@ fn test_clone_trait() { let f = U(S(Foo(0)), T(0)); let c = || { let _ = &f; - //~^ ERROR: `Clone` trait implementation for closure and drop order + //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements //~| NOTE: in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured 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 2bcf9a795edbd..bca935843e010 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 @@ -20,7 +20,7 @@ fn test_send_trait() { let mut f = 10; let fptr = SendPointer(&mut f as *mut i32); thread::spawn(move || unsafe { - //~^ ERROR: `Send` trait implementation for closure + //~^ ERROR: changes to closure capture //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured @@ -40,8 +40,9 @@ 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 for closure - //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send` + //~^ ERROR: changes to closure capture + //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` as `fptr.0.0` does not implement `Sync` + //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0.0` does not implement `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0.0 = 20; @@ -64,7 +65,7 @@ impl Clone for U { fn test_clone_trait() { let f = U(S(Foo(0)), T(0)); let c = || { - //~^ ERROR: `Clone` trait implementation for closure and drop order + //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements //~| NOTE: in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured 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 8d2d3553d4040..9bdc2f48194bf 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr @@ -1,4 +1,4 @@ -error: changes to closure capture in Rust 2021 will affect `Send` trait implementation for closure +error: changes to closure capture in Rust 2021 will affect which traits the closure implements --> $DIR/auto_traits.rs:22:19 | LL | thread::spawn(move || unsafe { @@ -23,11 +23,14 @@ LL | LL | *fptr.0 = 20; ... -error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure +error: changes to closure capture in Rust 2021 will affect which traits the closure implements --> $DIR/auto_traits.rs:42:19 | LL | thread::spawn(move || unsafe { - | ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send` + | ^^^^^^^^^^^^^^ + | | + | in Rust 2018, this closure implements `Sync` as `fptr` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` as `fptr.0.0` does not implement `Sync` + | in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0.0` does not implement `Send` ... LL | *fptr.0.0 = 20; | --------- in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0.0` @@ -40,11 +43,11 @@ LL | LL | LL | LL | -LL | *fptr.0.0 = 20; +LL | ... -error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order - --> $DIR/auto_traits.rs:66:13 +error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements + --> $DIR/auto_traits.rs:67:13 | LL | let c = || { | ^^ in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` 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 a5652154682c5..3cb72d679a5d5 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed @@ -19,8 +19,9 @@ where let f = panic::AssertUnwindSafe(f); let result = panic::catch_unwind(move || { let _ = &f; - //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe` + //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] + //~| NOTE: in Rust 2018, this closure implements `UnwindSafe` as `f` implements `UnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe` as `f.0` does not implement `UnwindSafe` + //~| NOTE: in Rust 2018, this closure implements `RefUnwindSafe` as `f` implements `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `RefUnwindSafe` as `f.0` does not implement `RefUnwindSafe` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured f.0() diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs index d9acde073fc3d..783c4034af2dc 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs @@ -18,8 +18,9 @@ where { let f = panic::AssertUnwindSafe(f); let result = panic::catch_unwind(move || { - //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` trait implementation for closure - //~| NOTE: in Rust 2018, this closure implements `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe` + //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] + //~| NOTE: in Rust 2018, this closure implements `UnwindSafe` as `f` implements `UnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe` as `f.0` does not implement `UnwindSafe` + //~| NOTE: in Rust 2018, this closure implements `RefUnwindSafe` as `f` implements `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `RefUnwindSafe` as `f.0` does not implement `RefUnwindSafe` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured f.0() diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr index 10816b7bc3adf..6a469db6ebb0d 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,8 +1,11 @@ -error: changes to closure capture in Rust 2021 will affect `UnwindSafe`, `RefUnwindSafe` trait implementation for closure +error: changes to closure capture in Rust 2021 will affect which traits the closure implements --> $DIR/mir_calls_to_shims.rs:20:38 | LL | let result = panic::catch_unwind(move || { - | ^^^^^^^ in Rust 2018, this closure implements `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe` + | ^^^^^^^ + | | + | in Rust 2018, this closure implements `UnwindSafe` as `f` implements `UnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe` as `f.0` does not implement `UnwindSafe` + | in Rust 2018, this closure implements `RefUnwindSafe` as `f` implements `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `RefUnwindSafe` as `f.0` does not implement `RefUnwindSafe` ... LL | f.0() | --- in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.0` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed index 11218eff1337f..7a7b1ec232133 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed @@ -18,7 +18,6 @@ impl Foo { } } - struct S(Foo); #[derive(Clone)] @@ -37,7 +36,7 @@ fn test_multi_issues() { let f2 = U(S(Foo::from("bar")), T(0)); let c = || { let _ = (&f1, &f2); - //~^ ERROR: `Clone` trait implementation for closure and drop order + //~^ ERROR: changes to closure capture in Rust 2021 //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will 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 @@ -57,7 +56,7 @@ fn test_capturing_all_disjoint_fields_individually() { let f1 = U(S(Foo::from("foo")), T(0)); let c = || { let _ = &f1; - //~^ ERROR: `Clone` trait implementation for closure + //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will 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 @@ -83,7 +82,7 @@ fn test_capturing_several_disjoint_fields_individually_1() { let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { let _ = &f1; - //~^ ERROR: `Clone` trait implementation for closure + //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.2` does not implement `Clone` //~| NOTE: for more information, see @@ -103,7 +102,7 @@ fn test_capturing_several_disjoint_fields_individually_2() { let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { let _ = &f1; - //~^ ERROR: `Clone` trait implementation for closure and drop order + //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will 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 @@ -136,8 +135,9 @@ fn test_multi_traits_issues() { 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 implements `Sync`, `Send` as `fptr1` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr1.0.0` does not implement `Sync`, `Send` + //~^ ERROR: changes to closure capture in Rust 2021 + //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` as `fptr1.0.0` does not implement `Sync` + //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr1.0.0` does not implement `Send` //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will 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 diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs index 02f2faa2e8741..9efe79c5971c6 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs @@ -18,7 +18,6 @@ impl Foo { } } - struct S(Foo); #[derive(Clone)] @@ -36,7 +35,7 @@ fn test_multi_issues() { let f1 = U(S(Foo::from("foo")), T(0)); let f2 = U(S(Foo::from("bar")), T(0)); let c = || { - //~^ ERROR: `Clone` trait implementation for closure and drop order + //~^ ERROR: changes to closure capture in Rust 2021 //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will 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 @@ -55,7 +54,7 @@ fn test_multi_issues() { fn test_capturing_all_disjoint_fields_individually() { let f1 = U(S(Foo::from("foo")), T(0)); let c = || { - //~^ ERROR: `Clone` trait implementation for closure + //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will 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 @@ -80,7 +79,7 @@ impl Clone for U1 { fn test_capturing_several_disjoint_fields_individually_1() { let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { - //~^ ERROR: `Clone` trait implementation for closure + //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.2` does not implement `Clone` //~| NOTE: for more information, see @@ -99,7 +98,7 @@ fn test_capturing_several_disjoint_fields_individually_1() { fn test_capturing_several_disjoint_fields_individually_2() { let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { - //~^ ERROR: `Clone` trait implementation for closure and drop order + //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will 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 @@ -132,8 +131,9 @@ fn test_multi_traits_issues() { 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 implements `Sync`, `Send` as `fptr1` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr1.0.0` does not implement `Sync`, `Send` + //~^ ERROR: changes to closure capture in Rust 2021 + //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` as `fptr1.0.0` does not implement `Sync` + //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr1.0.0` does not implement `Send` //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will 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 diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr index d425db5aa998c..02492283b7f58 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr @@ -1,5 +1,5 @@ -error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order - --> $DIR/multi_diagnostics.rs:38:13 +error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements + --> $DIR/multi_diagnostics.rs:37:13 | LL | let c = || { | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` @@ -25,8 +25,8 @@ LL ~ let c = || { LL + let _ = (&f1, &f2); | -error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure - --> $DIR/multi_diagnostics.rs:57:13 +error: changes to closure capture in Rust 2021 will affect which traits the closure implements + --> $DIR/multi_diagnostics.rs:56:13 | LL | let c = || { | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` @@ -41,8 +41,8 @@ LL ~ let c = || { LL + let _ = &f1; | -error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure - --> $DIR/multi_diagnostics.rs:82:13 +error: changes to closure capture in Rust 2021 will affect which traits the closure implements + --> $DIR/multi_diagnostics.rs:81:13 | LL | let c = || { | ^^ @@ -63,8 +63,8 @@ LL ~ let c = || { LL + let _ = &f1; | -error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order - --> $DIR/multi_diagnostics.rs:101:13 +error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements + --> $DIR/multi_diagnostics.rs:100:13 | LL | let c = || { | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` @@ -88,13 +88,14 @@ LL ~ let c = || { LL + let _ = &f1; | -error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure - --> $DIR/multi_diagnostics.rs:134:19 +error: changes to closure capture in Rust 2021 will affect which traits the closure implements + --> $DIR/multi_diagnostics.rs:133:19 | LL | thread::spawn(move || unsafe { | ^^^^^^^^^^^^^^ | | - | in Rust 2018, this closure implements `Sync`, `Send` as `fptr1` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr1.0.0` does not implement `Sync`, `Send` + | in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` as `fptr1.0.0` does not implement `Sync` + | in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr1.0.0` does not implement `Send` | in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr2.0` does not implement `Send` ... LL | *fptr1.0.0 = 20; From fc8113d04e5ea4ae5c053388b503eb7013006e26 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 4 Nov 2021 21:26:47 -0400 Subject: [PATCH 3/4] handle case of a variable not captured --- compiler/rustc_typeck/src/check/upvar.rs | 30 +++++++++++----- .../2229_closure_analysis/issue-90465.fixed | 35 +++++++++++++++++++ .../2229_closure_analysis/issue-90465.rs | 34 ++++++++++++++++++ .../2229_closure_analysis/issue-90465.stderr | 26 ++++++++++++++ 4 files changed, 117 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/closures/2229_closure_analysis/issue-90465.fixed create mode 100644 src/test/ui/closures/2229_closure_analysis/issue-90465.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/issue-90465.stderr diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index ef618ff51edc0..a141fdd7b88da 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -90,10 +90,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { enum CapturesInfo { /// We previously captured all of `x`, but now we capture some sub-path. CapturingLess { source_expr: Option, var_name: String }, - //CapturingNothing { - // // where the variable appears in the closure (but is not captured) - // use_span: Span, - //}, + CapturingNothing { + // where the variable appears in the closure (but is not captured) + use_span: Span, + }, } /// Reasons that we might issue a migration warning. @@ -758,6 +758,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { captured_name, )); } + CapturesInfo::CapturingNothing { use_span } => { + diagnostics_builder.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect", + self.tcx.hir().name(*var_hir_id), + )); + } + _ => { } } @@ -773,6 +779,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { captured_name, )); } + CapturesInfo::CapturingNothing { use_span: _ } => { + diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure", + v = self.tcx.hir().name(*var_hir_id), + )); + } } } @@ -787,6 +798,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { p = captured_name, )); } + + // Cannot happen: if we don't capture a variable, we impl strictly more traits + CapturesInfo::CapturingNothing { use_span } => span_bug!(*use_span, "missing trait from not capturing something"), } } } @@ -1051,10 +1065,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match closure_clause { // Only migrate if closure is a move closure hir::CaptureBy::Value => { - let diagnostics_info = FxHashSet::default(); - //diagnostics_info.insert(CapturesInfo::CapturingNothing); - //let upvars = self.tcx.upvars_mentioned(closure_def_id).expect("must be an upvar"); - //let _span = upvars[&var_hir_id]; + let mut diagnostics_info = FxHashSet::default(); + let upvars = self.tcx.upvars_mentioned(closure_def_id).expect("must be an upvar"); + let upvar = upvars[&var_hir_id]; + diagnostics_info.insert(CapturesInfo::CapturingNothing { use_span: upvar.span }); return Some(diagnostics_info); } hir::CaptureBy::Ref => {} diff --git a/src/test/ui/closures/2229_closure_analysis/issue-90465.fixed b/src/test/ui/closures/2229_closure_analysis/issue-90465.fixed new file mode 100644 index 0000000000000..4e0b18e72338a --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/issue-90465.fixed @@ -0,0 +1,35 @@ +// run-rustfix + +#![deny(rust_2021_incompatible_closure_captures)] +//~^ NOTE lint level is defined here + +fn main() { + struct Foo(u32); + impl Drop for Foo { + fn drop(&mut self) { + println!("dropped {}", self.0); + } + } + + let f0 = Foo(0); + let f1 = Foo(1); + + let c0 = move || { + let _ = &f0; + //~^ ERROR changes to closure capture in Rust 2021 will affect drop order + //~| NOTE for more information + let _ = f0; + //~^ NOTE in Rust 2018, this causes the closure to capture `f0`, but in Rust 2021, it has no effect + }; + + let c1 = move || { + let _ = &f1; + }; + + println!("dropping 0"); + drop(c0); + println!("dropping 1"); + drop(c1); + println!("dropped all"); +} +//~^ NOTE in Rust 2018, `f0` is dropped here along with the closure, but in Rust 2021 `f0` is not part of the closure diff --git a/src/test/ui/closures/2229_closure_analysis/issue-90465.rs b/src/test/ui/closures/2229_closure_analysis/issue-90465.rs new file mode 100644 index 0000000000000..466e6dbabc502 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/issue-90465.rs @@ -0,0 +1,34 @@ +// run-rustfix + +#![deny(rust_2021_incompatible_closure_captures)] +//~^ NOTE lint level is defined here + +fn main() { + struct Foo(u32); + impl Drop for Foo { + fn drop(&mut self) { + println!("dropped {}", self.0); + } + } + + let f0 = Foo(0); + let f1 = Foo(1); + + let c0 = move || { + //~^ ERROR changes to closure capture in Rust 2021 will affect drop order + //~| NOTE for more information + let _ = f0; + //~^ NOTE in Rust 2018, this causes the closure to capture `f0`, but in Rust 2021, it has no effect + }; + + let c1 = move || { + let _ = &f1; + }; + + println!("dropping 0"); + drop(c0); + println!("dropping 1"); + drop(c1); + println!("dropped all"); +} +//~^ NOTE in Rust 2018, `f0` is dropped here along with the closure, but in Rust 2021 `f0` is not part of the closure diff --git a/src/test/ui/closures/2229_closure_analysis/issue-90465.stderr b/src/test/ui/closures/2229_closure_analysis/issue-90465.stderr new file mode 100644 index 0000000000000..3e921dc0f8a66 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/issue-90465.stderr @@ -0,0 +1,26 @@ +error: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/issue-90465.rs:17:14 + | +LL | let c0 = move || { + | ^^^^^^^ +... +LL | let _ = f0; + | -- in Rust 2018, this causes the closure to capture `f0`, but in Rust 2021, it has no effect +... +LL | } + | - in Rust 2018, `f0` is dropped here along with the closure, but in Rust 2021 `f0` is not part of the closure + | +note: the lint level is defined here + --> $DIR/issue-90465.rs:3:9 + | +LL | #![deny(rust_2021_incompatible_closure_captures)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: for more information, see +help: add a dummy let to cause `f0` to be fully captured + | +LL ~ let c0 = move || { +LL + let _ = &f0; + | + +error: aborting due to previous error + From 4154e8acf045a13bf57bc9b3c487f838f17230c8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 5 Nov 2021 12:43:42 -0400 Subject: [PATCH 4/4] apply suggestions from code review --- compiler/rustc_typeck/src/check/upvar.rs | 40 ++++++++++--------- .../migrations/auto_traits.fixed | 8 ++-- .../migrations/auto_traits.rs | 8 ++-- .../migrations/auto_traits.stderr | 8 ++-- .../migrations/mir_calls_to_shims.fixed | 4 +- .../migrations/mir_calls_to_shims.rs | 4 +- .../migrations/mir_calls_to_shims.stderr | 4 +- .../migrations/multi_diagnostics.fixed | 16 ++++---- .../migrations/multi_diagnostics.rs | 16 ++++---- .../migrations/multi_diagnostics.stderr | 16 ++++---- 10 files changed, 63 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index a141fdd7b88da..774d8078e52ca 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -87,9 +87,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// corresponding place being captured and a String which contains the captured value's /// name (i.e: a.b.c) #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -enum CapturesInfo { +enum UpvarMigrationInfo { /// We previously captured all of `x`, but now we capture some sub-path. - CapturingLess { source_expr: Option, var_name: String }, + CapturingPrecise { source_expr: Option, var_name: String }, CapturingNothing { // where the variable appears in the closure (but is not captured) use_span: Span, @@ -123,7 +123,7 @@ impl MigrationWarningReason { /// Intermediate format to store information needed to generate a note in the migration lint. struct MigrationLintNote { - captures_info: CapturesInfo, + captures_info: UpvarMigrationInfo, /// reasons why migration is needed for this capture reason: MigrationWarningReason, @@ -751,14 +751,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // for migration being needed for lint_note in diagnostics_info.iter() { match &lint_note.captures_info { - CapturesInfo::CapturingLess { source_expr: Some(capture_expr_id), var_name: captured_name } => { + UpvarMigrationInfo::CapturingPrecise { source_expr: Some(capture_expr_id), var_name: captured_name } => { let cause_span = self.tcx.hir().span(*capture_expr_id); diagnostics_builder.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`", self.tcx.hir().name(*var_hir_id), captured_name, )); } - CapturesInfo::CapturingNothing { use_span } => { + UpvarMigrationInfo::CapturingNothing { use_span } => { diagnostics_builder.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect", self.tcx.hir().name(*var_hir_id), )); @@ -773,13 +773,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let drop_location_span = drop_location_span(self.tcx, &closure_hir_id); match &lint_note.captures_info { - CapturesInfo::CapturingLess { var_name: captured_name, .. } => { + UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => { diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure", self.tcx.hir().name(*var_hir_id), captured_name, )); } - CapturesInfo::CapturingNothing { use_span: _ } => { + UpvarMigrationInfo::CapturingNothing { use_span: _ } => { diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure", v = self.tcx.hir().name(*var_hir_id), )); @@ -791,16 +791,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for &missing_trait in &lint_note.reason.auto_traits { // not capturing something anymore cannot cause a trait to fail to be implemented: match &lint_note.captures_info { - CapturesInfo::CapturingLess { var_name: captured_name, .. } => { - diagnostics_builder.span_label(closure_head_span, format!("in Rust 2018, this closure implements {missing_trait} as `{x}` implements {missing_trait}, but in Rust 2021, this closure will no longer implement {missing_trait} as `{p}` does not implement {missing_trait}", - missing_trait = missing_trait, - x = self.tcx.hir().name(*var_hir_id), - p = captured_name, - )); + UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => { + let var_name = self.tcx.hir().name(*var_hir_id); + diagnostics_builder.span_label(closure_head_span, format!("\ + in Rust 2018, this closure implements {missing_trait} \ + as `{var_name}` implements {missing_trait}, but in Rust 2021, \ + this closure will no longer implement {missing_trait} \ + because `{var_name}` is not fully captured \ + and `{captured_name}` does not implement {missing_trait}")); } // Cannot happen: if we don't capture a variable, we impl strictly more traits - CapturesInfo::CapturingNothing { use_span } => span_bug!(*use_span, "missing trait from not capturing something"), + UpvarMigrationInfo::CapturingNothing { use_span } => span_bug!(*use_span, "missing trait from not capturing something"), } } } @@ -919,7 +921,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, var_hir_id: hir::HirId, closure_clause: hir::CaptureBy, - ) -> Option>> { + ) -> Option>> { let auto_traits_def_id = vec![ self.tcx.lang_items().clone_trait(), self.tcx.lang_items().sync_trait(), @@ -1008,7 +1010,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !capture_problems.is_empty() { problematic_captures.insert( - CapturesInfo::CapturingLess { + UpvarMigrationInfo::CapturingPrecise { source_expr: capture.info.path_expr_id, var_name: capture.to_string(self.tcx), }, @@ -1042,7 +1044,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>, closure_clause: hir::CaptureBy, var_hir_id: hir::HirId, - ) -> Option> { + ) -> 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())) { @@ -1068,7 +1070,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut diagnostics_info = FxHashSet::default(); let upvars = self.tcx.upvars_mentioned(closure_def_id).expect("must be an upvar"); let upvar = upvars[&var_hir_id]; - diagnostics_info.insert(CapturesInfo::CapturingNothing { use_span: upvar.span }); + diagnostics_info.insert(UpvarMigrationInfo::CapturingNothing { use_span: upvar.span }); return Some(diagnostics_info); } hir::CaptureBy::Ref => {} @@ -1086,7 +1088,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Only care about captures that are moved into the closure ty::UpvarCapture::ByValue(..) => { projections_list.push(captured_place.place.projections.as_slice()); - diagnostics_info.insert(CapturesInfo::CapturingLess { + diagnostics_info.insert(UpvarMigrationInfo::CapturingPrecise { source_expr: captured_place.info.path_expr_id, var_name: captured_place.to_string(self.tcx), }); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed index b938b8429537e..26703fbf81193 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 @@ -21,7 +21,7 @@ fn test_send_trait() { let fptr = SendPointer(&mut f as *mut i32); thread::spawn(move || { let _ = &fptr; unsafe { //~^ ERROR: changes to closure capture - //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send` + //~| NOTE: in Rust 2018, this closure implements `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0 = 20; @@ -41,8 +41,8 @@ fn test_sync_trait() { let fptr = SyncPointer(f); thread::spawn(move || { let _ = &fptr; unsafe { //~^ ERROR: changes to closure capture - //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` as `fptr.0.0` does not implement `Sync` - //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0.0` does not implement `Send` + //~| NOTE: in Rust 2018, this closure implements `Sync` + //~| NOTE: in Rust 2018, this closure implements `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0.0 = 20; @@ -67,7 +67,7 @@ fn test_clone_trait() { let c = || { let _ = &f; //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` + //~| NOTE: in Rust 2018, this closure implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured let f_1 = f.1; diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs index bca935843e010..932db51d43713 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 @@ -21,7 +21,7 @@ fn test_send_trait() { let fptr = SendPointer(&mut f as *mut i32); thread::spawn(move || unsafe { //~^ ERROR: changes to closure capture - //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send` + //~| NOTE: in Rust 2018, this closure implements `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0 = 20; @@ -41,8 +41,8 @@ fn test_sync_trait() { let fptr = SyncPointer(f); thread::spawn(move || unsafe { //~^ ERROR: changes to closure capture - //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` as `fptr.0.0` does not implement `Sync` - //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0.0` does not implement `Send` + //~| NOTE: in Rust 2018, this closure implements `Sync` + //~| NOTE: in Rust 2018, this closure implements `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr` to be fully captured *fptr.0.0 = 20; @@ -66,7 +66,7 @@ fn test_clone_trait() { let f = U(S(Foo(0)), T(0)); let c = || { //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` + //~| NOTE: in Rust 2018, this closure implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured let f_1 = f.1; diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr index 9bdc2f48194bf..ee4907bb755cc 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr @@ -2,7 +2,7 @@ error: changes to closure capture in Rust 2021 will affect which traits the clos --> $DIR/auto_traits.rs:22:19 | LL | thread::spawn(move || unsafe { - | ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send` + | ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr` is not fully captured and `fptr.0` does not implement `Send` ... LL | *fptr.0 = 20; | ------- in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0` @@ -29,8 +29,8 @@ error: changes to closure capture in Rust 2021 will affect which traits the clos LL | thread::spawn(move || unsafe { | ^^^^^^^^^^^^^^ | | - | in Rust 2018, this closure implements `Sync` as `fptr` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` as `fptr.0.0` does not implement `Sync` - | in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0.0` does not implement `Send` + | in Rust 2018, this closure implements `Sync` as `fptr` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr` is not fully captured and `fptr.0.0` does not implement `Sync` + | in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr` is not fully captured and `fptr.0.0` does not implement `Send` ... LL | *fptr.0.0 = 20; | --------- in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0.0` @@ -50,7 +50,7 @@ error: changes to closure capture in Rust 2021 will affect drop order and which --> $DIR/auto_traits.rs:67:13 | LL | let c = || { - | ^^ in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` + | ^^ in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f` is not fully captured and `f.1` does not implement `Clone` ... LL | let f_1 = f.1; | --- in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.1` 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 3cb72d679a5d5..7df0dd76b4456 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 @@ -20,8 +20,8 @@ where let result = panic::catch_unwind(move || { let _ = &f; //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] - //~| NOTE: in Rust 2018, this closure implements `UnwindSafe` as `f` implements `UnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe` as `f.0` does not implement `UnwindSafe` - //~| NOTE: in Rust 2018, this closure implements `RefUnwindSafe` as `f` implements `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `RefUnwindSafe` as `f.0` does not implement `RefUnwindSafe` + //~| NOTE: in Rust 2018, this closure implements `UnwindSafe` + //~| NOTE: in Rust 2018, this closure implements `RefUnwindSafe` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured f.0() diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs index 783c4034af2dc..d02fac7c66952 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs @@ -19,8 +19,8 @@ where let f = panic::AssertUnwindSafe(f); let result = panic::catch_unwind(move || { //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] - //~| NOTE: in Rust 2018, this closure implements `UnwindSafe` as `f` implements `UnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe` as `f.0` does not implement `UnwindSafe` - //~| NOTE: in Rust 2018, this closure implements `RefUnwindSafe` as `f` implements `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `RefUnwindSafe` as `f.0` does not implement `RefUnwindSafe` + //~| NOTE: in Rust 2018, this closure implements `UnwindSafe` + //~| NOTE: in Rust 2018, this closure implements `RefUnwindSafe` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f` to be fully captured f.0() diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr index 6a469db6ebb0d..74f85b6ebaac5 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 @@ -4,8 +4,8 @@ error: changes to closure capture in Rust 2021 will affect which traits the clos LL | let result = panic::catch_unwind(move || { | ^^^^^^^ | | - | in Rust 2018, this closure implements `UnwindSafe` as `f` implements `UnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe` as `f.0` does not implement `UnwindSafe` - | in Rust 2018, this closure implements `RefUnwindSafe` as `f` implements `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `RefUnwindSafe` as `f.0` does not implement `RefUnwindSafe` + | in Rust 2018, this closure implements `UnwindSafe` as `f` implements `UnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe` because `f` is not fully captured and `f.0` does not implement `UnwindSafe` + | in Rust 2018, this closure implements `RefUnwindSafe` as `f` implements `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `RefUnwindSafe` because `f` is not fully captured and `f.0` does not implement `RefUnwindSafe` ... LL | f.0() | --- in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.0` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed index 7a7b1ec232133..2b86b0ddade23 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed @@ -37,7 +37,7 @@ fn test_multi_issues() { let c = || { let _ = (&f1, &f2); //~^ ERROR: changes to closure capture in Rust 2021 - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1`, `f2` to be fully captured let _f_1 = f1.0; @@ -57,7 +57,7 @@ fn test_capturing_all_disjoint_fields_individually() { let c = || { let _ = &f1; //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1` to be fully captured let _f_1 = f1.0; @@ -83,8 +83,8 @@ fn test_capturing_several_disjoint_fields_individually_1() { let c = || { let _ = &f1; //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.2` does not implement `Clone` + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1` to be fully captured let _f_0 = f1.0; @@ -103,7 +103,7 @@ fn test_capturing_several_disjoint_fields_individually_2() { let c = || { let _ = &f1; //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1` to be fully captured let _f_0 = f1.0; @@ -136,9 +136,9 @@ fn test_multi_traits_issues() { let fptr2 = SendPointer(&mut f2 as *mut i32); thread::spawn(move || { let _ = (&fptr1, &fptr2); unsafe { //~^ ERROR: changes to closure capture in Rust 2021 - //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` as `fptr1.0.0` does not implement `Sync` - //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr1.0.0` does not implement `Send` - //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr2.0` does not implement `Send` + //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync` + //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr1` implements `Send` + //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr1`, `fptr2` to be fully captured *fptr1.0.0 = 20; diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs index 9efe79c5971c6..3cac4abfad7c2 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs @@ -36,7 +36,7 @@ fn test_multi_issues() { let f2 = U(S(Foo::from("bar")), T(0)); let c = || { //~^ ERROR: changes to closure capture in Rust 2021 - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1`, `f2` to be fully captured let _f_1 = f1.0; @@ -55,7 +55,7 @@ fn test_capturing_all_disjoint_fields_individually() { let f1 = U(S(Foo::from("foo")), T(0)); let c = || { //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1` to be fully captured let _f_1 = f1.0; @@ -80,8 +80,8 @@ fn test_capturing_several_disjoint_fields_individually_1() { let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures] - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.2` does not implement `Clone` + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1` to be fully captured let _f_0 = f1.0; @@ -99,7 +99,7 @@ fn test_capturing_several_disjoint_fields_individually_2() { let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements - //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `f1` to be fully captured let _f_0 = f1.0; @@ -132,9 +132,9 @@ fn test_multi_traits_issues() { let fptr2 = SendPointer(&mut f2 as *mut i32); thread::spawn(move || unsafe { //~^ ERROR: changes to closure capture in Rust 2021 - //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` as `fptr1.0.0` does not implement `Sync` - //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr1.0.0` does not implement `Send` - //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr2.0` does not implement `Send` + //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync` + //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr1` implements `Send` + //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send` //~| NOTE: for more information, see //~| HELP: add a dummy let to cause `fptr1`, `fptr2` to be fully captured *fptr1.0.0 = 20; diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr index 02492283b7f58..0008f1b2c07ed 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr @@ -2,7 +2,7 @@ error: changes to closure capture in Rust 2021 will affect drop order and which --> $DIR/multi_diagnostics.rs:37:13 | LL | let c = || { - | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone` ... LL | let _f_1 = f1.0; | ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0` @@ -29,7 +29,7 @@ error: changes to closure capture in Rust 2021 will affect which traits the clos --> $DIR/multi_diagnostics.rs:56:13 | LL | let c = || { - | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone` ... LL | let _f_1 = f1.0; | ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0` @@ -47,8 +47,8 @@ error: changes to closure capture in Rust 2021 will affect which traits the clos LL | let c = || { | ^^ | | - | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` - | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.2` does not implement `Clone` + | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone` + | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.2` does not implement `Clone` ... LL | let _f_0 = f1.0; | ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0` @@ -67,7 +67,7 @@ error: changes to closure capture in Rust 2021 will affect drop order and which --> $DIR/multi_diagnostics.rs:100:13 | LL | let c = || { - | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` + | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone` ... LL | let _f_0 = f1.0; | ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0` @@ -94,9 +94,9 @@ error: changes to closure capture in Rust 2021 will affect which traits the clos LL | thread::spawn(move || unsafe { | ^^^^^^^^^^^^^^ | | - | in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` as `fptr1.0.0` does not implement `Sync` - | in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr1.0.0` does not implement `Send` - | in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr2.0` does not implement `Send` + | in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr1` is not fully captured and `fptr1.0.0` does not implement `Sync` + | in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr1` is not fully captured and `fptr1.0.0` does not implement `Send` + | in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr2` is not fully captured and `fptr2.0` does not implement `Send` ... LL | *fptr1.0.0 = 20; | ---------- in Rust 2018, this closure captures all of `fptr1`, but in Rust 2021, it will only capture `fptr1.0.0`