about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs30
-rw-r--r--src/test/ui/closures/2229_closure_analysis/issue-90465.fixed35
-rw-r--r--src/test/ui/closures/2229_closure_analysis/issue-90465.rs34
-rw-r--r--src/test/ui/closures/2229_closure_analysis/issue-90465.stderr26
4 files changed, 117 insertions, 8 deletions
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index ef618ff51ed..a141fdd7b88 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<hir::HirId>, 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 00000000000..4e0b18e7233
--- /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 00000000000..466e6dbabc5
--- /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 00000000000..3e921dc0f8a
--- /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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+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
+