]> git.lizzy.rs Git - rust.git/commitdiff
Detect closures assigned to binding in block
authorEsteban Küber <esteban@kuber.com.ar>
Thu, 5 Jan 2023 21:29:36 +0000 (21:29 +0000)
committerEsteban Küber <esteban@kuber.com.ar>
Thu, 5 Jan 2023 21:29:36 +0000 (21:29 +0000)
Fix #58497.

compiler/rustc_borrowck/src/borrowck_errors.rs
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
compiler/rustc_borrowck/src/diagnostics/region_name.rs
src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs
src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr
src/test/ui/unboxed-closures/unboxed-closure-region.rs
src/test/ui/unboxed-closures/unboxed-closure-region.stderr
src/tools/rustfmt/tests/target/issue_4110.rs

index e4942f9b666e0e837389503cd2d1099895b318da..a4943d112042dc212d419f0247933a88cecb158a 100644 (file)
@@ -440,15 +440,14 @@ pub(crate) fn cannot_capture_in_long_lived_closure(
         closure_kind: &str,
         borrowed_path: &str,
         capture_span: Span,
+        scope: &str,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let mut err = struct_span_err!(
             self,
             closure_span,
             E0373,
-            "{} may outlive the current function, but it borrows {}, which is owned by the current \
-             function",
-            closure_kind,
-            borrowed_path,
+            "{closure_kind} may outlive the current {scope}, but it borrows {borrowed_path}, \
+             which is owned by the current {scope}",
         );
         err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
             .span_label(closure_span, format!("may outlive borrowed value {}", borrowed_path));
index 492c8d02012671e28d80b83741f83b8faa953513..d99bfc01a4298ccd50fb8d7fa0adec260065e361 100644 (file)
@@ -1423,6 +1423,21 @@ pub(crate) fn report_borrowed_value_does_not_live_long_enough(
             //
             // then just use the normal error. The closure isn't escaping
             // and `move` will not help here.
+            (
+                Some(name),
+                BorrowExplanation::UsedLater(LaterUseKind::ClosureCapture, var_or_use_span, _),
+            ) => self.report_escaping_closure_capture(
+                borrow_spans,
+                borrow_span,
+                &RegionName {
+                    name: self.synthesize_region_name(),
+                    source: RegionNameSource::Static,
+                },
+                ConstraintCategory::CallArgument(None),
+                var_or_use_span,
+                &format!("`{}`", name),
+                "block",
+            ),
             (
                 Some(name),
                 BorrowExplanation::MustBeValidFor {
@@ -1443,6 +1458,7 @@ pub(crate) fn report_borrowed_value_does_not_live_long_enough(
                     category,
                     span,
                     &format!("`{}`", name),
+                    "function",
                 ),
             (
                 name,
@@ -1895,6 +1911,7 @@ fn try_report_cannot_return_reference_to_local(
         Some(err)
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn report_escaping_closure_capture(
         &mut self,
         use_span: UseSpans<'tcx>,
@@ -1903,6 +1920,7 @@ fn report_escaping_closure_capture(
         category: ConstraintCategory<'tcx>,
         constraint_span: Span,
         captured_var: &str,
+        scope: &str,
     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
         let tcx = self.infcx.tcx;
         let args_span = use_span.args_or_use();
@@ -1933,8 +1951,13 @@ fn report_escaping_closure_capture(
             None => "closure",
         };
 
-        let mut err =
-            self.cannot_capture_in_long_lived_closure(args_span, kind, captured_var, var_span);
+        let mut err = self.cannot_capture_in_long_lived_closure(
+            args_span,
+            kind,
+            captured_var,
+            var_span,
+            scope,
+        );
         err.span_suggestion_verbose(
             sugg_span,
             &format!(
@@ -1956,10 +1979,10 @@ fn report_escaping_closure_capture(
                 if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) {
                     err.note(
                         "async blocks are not executed immediately and must either take a \
-                    reference or ownership of outside variables they use",
+                         reference or ownership of outside variables they use",
                     );
                 } else {
-                    let msg = format!("function requires argument type to outlive `{}`", fr_name);
+                    let msg = format!("{scope} requires argument type to outlive `{fr_name}`");
                     err.span_note(constraint_span, &msg);
                 }
             }
index 00f5e8a83972f9c6456c51635867e2a7bfa59227..c4ae30151c4bd2ee6eac2beea26dbed1d1438a4d 100644 (file)
@@ -444,6 +444,7 @@ pub(crate) fn explain_why_borrow_contains_point(
     /// First span returned points to the location of the conflicting use
     /// Second span if `Some` is returned in the case of closures and points
     /// to the use of the path
+    #[instrument(level = "debug", skip(self))]
     fn later_use_kind(
         &self,
         borrow: &BorrowData<'tcx>,
@@ -461,11 +462,18 @@ fn later_use_kind(
                 let block = &self.body.basic_blocks[location.block];
 
                 let kind = if let Some(&Statement {
-                    kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), _)),
+                    kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), place)),
                     ..
                 }) = block.statements.get(location.statement_index)
                 {
-                    LaterUseKind::FakeLetRead
+                    if let Some(l) = place.as_local()
+                        && let local_decl = &self.body.local_decls[l]
+                        && local_decl.ty.is_closure()
+                    {
+                        LaterUseKind::ClosureCapture
+                    } else {
+                        LaterUseKind::FakeLetRead
+                    }
                 } else if self.was_captured_by_trait_object(borrow) {
                     LaterUseKind::TraitCapture
                 } else if location.statement_index == block.statements.len() {
index dbd4cac7b1432f2e3785838144f09e49a41a4c2b..579ce90a760f2e977ee9a0a1e65da7827590c4ca 100644 (file)
@@ -200,7 +200,7 @@ pub(crate) fn mir_hir_id(&self) -> hir::HirId {
     /// increment the counter.
     ///
     /// This is _not_ idempotent. Call `give_region_a_name` when possible.
-    fn synthesize_region_name(&self) -> Symbol {
+    pub(crate) fn synthesize_region_name(&self) -> Symbol {
         let c = self.next_region_name.replace_with(|counter| *counter + 1);
         Symbol::intern(&format!("'{:?}", c))
     }
index bdd6cb79b60b09f414508c21884102b06cace66d..00f50c33e1ccdb6b64ffb17488756027661ea5d1 100644 (file)
@@ -8,10 +8,9 @@ struct Point {
 fn main() {
     let mut c = {
         let mut p = Point {x: "1".to_string(), y: "2".to_string() };
-        || {
+        || { //~ ERROR closure may outlive the current block, but it borrows `p`
            let x = &mut p.x;
            println!("{:?}", p);
-            //~^ ERROR `p` does not live long enough
         }
     };
     c();
index dab1809a381ee28a1e5241253069faadc37d8126..ee923804786852c807d88782b9caa5126d5ba775 100644 (file)
@@ -1,18 +1,22 @@
-error[E0597]: `p` does not live long enough
-  --> $DIR/borrowck-3.rs:13:29
+error[E0373]: closure may outlive the current block, but it borrows `p`, which is owned by the current block
+  --> $DIR/borrowck-3.rs:11:9
    |
-LL |     let mut c = {
-   |         ----- borrow later stored here
-LL |         let mut p = Point {x: "1".to_string(), y: "2".to_string() };
 LL |         || {
-   |         -- value captured here
+   |         ^^ may outlive borrowed value `p`
 LL |            let x = &mut p.x;
 LL |            println!("{:?}", p);
-   |                             ^ borrowed value does not live long enough
-...
-LL |     };
-   |     - `p` dropped here while still borrowed
+   |                             - `p` is borrowed here
+   |
+note: block requires argument type to outlive `'1`
+  --> $DIR/borrowck-3.rs:9:9
+   |
+LL |     let mut c = {
+   |         ^^^^^
+help: to force the closure to take ownership of `p` (and any other referenced variables), use the `move` keyword
+   |
+LL |         move || {
+   |         ++++
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0597`.
+For more information about this error, try `rustc --explain E0373`.
index f202492eda553ad4b5ec5eefe8aecf61914d8dfd..51fe118c93ff146c6f67d8da2cdf9437f1d21daa 100644 (file)
@@ -5,7 +5,7 @@
 fn main() {
     let _f = {
         let x = 0;
-        || x //~ ERROR `x` does not live long enough
+        || x //~ ERROR closure may outlive the current block, but it borrows `x`
     };
     _f;
 }
index b40b2f67d9bade1707c36211f30dfa55bc39c9ab..43e9af24a7c2bc0d655e0cb36b2145a6284fe741 100644 (file)
@@ -1,16 +1,21 @@
-error[E0597]: `x` does not live long enough
-  --> $DIR/unboxed-closure-region.rs:8:12
+error[E0373]: closure may outlive the current block, but it borrows `x`, which is owned by the current block
+  --> $DIR/unboxed-closure-region.rs:8:9
    |
-LL |     let _f = {
-   |         -- borrow later stored here
-LL |         let x = 0;
 LL |         || x
-   |         -- ^ borrowed value does not live long enough
+   |         ^^ - `x` is borrowed here
    |         |
-   |         value captured here
-LL |     };
-   |     - `x` dropped here while still borrowed
+   |         may outlive borrowed value `x`
+   |
+note: block requires argument type to outlive `'1`
+  --> $DIR/unboxed-closure-region.rs:6:9
+   |
+LL |     let _f = {
+   |         ^^
+help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword
+   |
+LL |         move || x
+   |         ++++
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0597`.
+For more information about this error, try `rustc --explain E0373`.
index 4a58c3946e12dae2c3ac6c441c60bc5c9b8b6f1f..d3734e90b7ffa97c47633d0a0b6909356ea26160 100644 (file)
@@ -20,6 +20,7 @@ fn bindings() {
                 category,
                 span,
                 &format!("`{}`", name),
+                "function",
             ),
         (
             ref name,