]> git.lizzy.rs Git - rust.git/commitdiff
Explain error when yielding a reference to a local variable
authorMatthew Jasper <mjjasper1@gmail.com>
Mon, 22 Apr 2019 17:20:19 +0000 (18:20 +0100)
committerMatthew Jasper <mjjasper1@gmail.com>
Mon, 22 Apr 2019 17:50:26 +0000 (18:50 +0100)
src/librustc_mir/borrow_check/error_reporting.rs
src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
src/librustc_mir/util/borrowck_errors.rs
src/test/ui/nll/issue-55850.rs
src/test/ui/nll/issue-55850.stderr

index 3ab0996d3a17f835d7d49f007f2bdcf82e1b5562..956e8c5627278818fb82d027ae6530ac11cc4eea 100644 (file)
@@ -826,18 +826,21 @@ fn report_local_value_does_not_live_long_enough(
 
         let borrow_span = borrow_spans.var_or_use();
         if let BorrowExplanation::MustBeValidFor {
-            category: ConstraintCategory::Return,
+            category,
             span,
             ref opt_place_desc,
             from_closure: false,
             ..
         } = explanation {
-            return self.report_cannot_return_reference_to_local(
+            if let Some(diag) = self.try_report_cannot_return_reference_to_local(
                 borrow,
                 borrow_span,
                 span,
+                category,
                 opt_place_desc.as_ref(),
-            );
+            ) {
+                return diag;
+            }
         }
 
         let mut err = self.infcx.tcx.path_does_not_live_long_enough(
@@ -1015,17 +1018,20 @@ fn report_temporary_value_does_not_live_long_enough(
         );
 
         if let BorrowExplanation::MustBeValidFor {
-            category: ConstraintCategory::Return,
+            category,
             span,
             from_closure: false,
             ..
         } = explanation {
-            return self.report_cannot_return_reference_to_local(
+            if let Some(diag) = self.try_report_cannot_return_reference_to_local(
                 borrow,
                 proper_span,
                 span,
+                category,
                 None,
-            );
+            ) {
+                return diag;
+            }
         }
 
         let tcx = self.infcx.tcx;
@@ -1064,15 +1070,22 @@ fn report_temporary_value_does_not_live_long_enough(
         err
     }
 
-    fn report_cannot_return_reference_to_local(
+    fn try_report_cannot_return_reference_to_local(
         &self,
         borrow: &BorrowData<'tcx>,
         borrow_span: Span,
         return_span: Span,
+        category: ConstraintCategory,
         opt_place_desc: Option<&String>,
-    ) -> DiagnosticBuilder<'cx> {
+    ) -> Option<DiagnosticBuilder<'cx>> {
         let tcx = self.infcx.tcx;
 
+        let return_kind = match category {
+            ConstraintCategory::Return => "return",
+            ConstraintCategory::Yield => "yield",
+            _ => return None,
+        };
+
         // FIXME use a better heuristic than Spans
         let reference_desc = if return_span == self.mir.source_info(borrow.reserve_location).span {
             "reference to"
@@ -1110,7 +1123,7 @@ fn report_cannot_return_reference_to_local(
             let local = if let Place::Base(PlaceBase::Local(local)) = *root_place {
                 local
             } else {
-                bug!("report_cannot_return_reference_to_local: not a local")
+                bug!("try_report_cannot_return_reference_to_local: not a local")
             };
             match self.mir.local_kind(local) {
                 LocalKind::ReturnPointer | LocalKind::Temp => {
@@ -1131,6 +1144,7 @@ fn report_cannot_return_reference_to_local(
 
         let mut err = tcx.cannot_return_reference_to_local(
             return_span,
+            return_kind,
             reference_desc,
             &place_desc,
             Origin::Mir,
@@ -1140,7 +1154,7 @@ fn report_cannot_return_reference_to_local(
             err.span_label(borrow_span, note);
         }
 
-        err
+        Some(err)
     }
 
     fn report_escaping_closure_capture(
index 5ad54080c5a6122ecb4eb67de048c4eea9422c35..5b1c64039bee3400c3aa6c9d452bc56c5684fe6e 100644 (file)
@@ -313,9 +313,13 @@ pub(in crate::borrow_check) fn explain_why_borrow_contains_point(
                             opt_place_desc,
                         }
                     } else {
+                        debug!("explain_why_borrow_contains_point: \
+                                Could not generate a region name");
                         BorrowExplanation::Unexplained
                     }
                 } else {
+                    debug!("explain_why_borrow_contains_point: \
+                            Could not generate an error region vid");
                     BorrowExplanation::Unexplained
                 }
             }
index 362214d3257123d5b54de71737686a0f60fd5160..e72d4c9e3d570752599d5a8cabc88e290546130b 100644 (file)
@@ -32,6 +32,7 @@
     MatchedAdtAndSegment(Span),
     AnonRegionFromUpvar(Span, String),
     AnonRegionFromOutput(Span, String, String),
+    AnonRegionFromYieldTy(Span, String),
 }
 
 impl RegionName {
@@ -46,7 +47,8 @@ impl RegionName {
             RegionNameSource::MatchedHirTy(..) |
             RegionNameSource::MatchedAdtAndSegment(..) |
             RegionNameSource::AnonRegionFromUpvar(..) |
-            RegionNameSource::AnonRegionFromOutput(..) => false,
+            RegionNameSource::AnonRegionFromOutput(..) |
+            RegionNameSource::AnonRegionFromYieldTy(..) => false,
         }
     }
 
@@ -103,6 +105,12 @@ impl RegionName {
                     format!("return type{} is {}", mir_description, type_name),
                 );
             },
+            RegionNameSource::AnonRegionFromYieldTy(span, type_name) => {
+                diag.span_label(
+                    *span,
+                    format!("yield type is {}", type_name),
+                );
+            }
             RegionNameSource::Static => {},
         }
     }
@@ -167,6 +175,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 self.give_name_if_anonymous_region_appears_in_output(
                     infcx, mir, mir_def_id, fr, counter,
                 )
+            })
+            .or_else(|| {
+                self.give_name_if_anonymous_region_appears_in_yield_ty(
+                    infcx, mir, mir_def_id, fr, counter,
+                )
             });
 
         debug!("give_region_a_name: gave name {:?}", value);
@@ -673,10 +686,7 @@ fn give_name_if_anonymous_region_appears_in_output(
             "give_name_if_anonymous_region_appears_in_output: return_ty = {:?}",
             return_ty
         );
-        if !infcx
-            .tcx
-            .any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr)
-        {
+        if !tcx.any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr) {
             return None;
         }
 
@@ -721,6 +731,57 @@ fn give_name_if_anonymous_region_appears_in_output(
         })
     }
 
+    fn give_name_if_anonymous_region_appears_in_yield_ty(
+        &self,
+        infcx: &InferCtxt<'_, '_, 'tcx>,
+        mir: &Mir<'tcx>,
+        mir_def_id: DefId,
+        fr: RegionVid,
+        counter: &mut usize,
+    ) -> Option<RegionName> {
+        // Note: generators from `async fn` yield `()`, so we don't have to
+        // worry about them here.
+        let yield_ty = self.universal_regions.yield_ty?;
+        debug!(
+            "give_name_if_anonymous_region_appears_in_yield_ty: yield_ty = {:?}",
+            yield_ty,
+        );
+
+        let tcx = infcx.tcx;
+
+        if !tcx.any_free_region_meets(&yield_ty, |r| r.to_region_vid() == fr) {
+            return None;
+        }
+
+        let mut highlight = RegionHighlightMode::default();
+        highlight.highlighting_region_vid(fr, *counter);
+        let type_name = infcx.extract_type_name(&yield_ty, Some(highlight));
+
+        let mir_node_id = tcx.hir().as_local_node_id(mir_def_id).expect("non-local mir");
+
+        let yield_span = match tcx.hir().get(mir_node_id) {
+            hir::Node::Expr(hir::Expr {
+                node: hir::ExprKind::Closure(_, _, _, span, _),
+                ..
+            }) => (
+                tcx.sess.source_map().end_point(*span)
+            ),
+            _ => mir.span,
+        };
+
+        debug!(
+            "give_name_if_anonymous_region_appears_in_yield_ty: \
+             type_name = {:?}, yield_span = {:?}",
+            yield_span,
+            type_name,
+        );
+
+        Some(RegionName {
+            name: self.synthesize_region_name(counter),
+            source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name),
+        })
+    }
+
     /// Creates a synthetic region named `'1`, incrementing the
     /// counter.
     fn synthesize_region_name(&self, counter: &mut usize) -> InternedString {
index e334e27cc855663e12527bb4a009c0e78ac4c347..0cbe39ab6d43477d436c73377d70e45dc5b5eb50 100644 (file)
@@ -650,6 +650,7 @@ fn path_does_not_live_long_enough(
     fn cannot_return_reference_to_local(
         self,
         span: Span,
+        return_kind: &str,
         reference_desc: &str,
         path_desc: &str,
         o: Origin,
@@ -658,7 +659,8 @@ fn cannot_return_reference_to_local(
             self,
             span,
             E0515,
-            "cannot return {REFERENCE} {LOCAL}{OGN}",
+            "cannot {RETURN} {REFERENCE} {LOCAL}{OGN}",
+            RETURN=return_kind,
             REFERENCE=reference_desc,
             LOCAL=path_desc,
             OGN = o
@@ -666,7 +668,7 @@ fn cannot_return_reference_to_local(
 
         err.span_label(
             span,
-            format!("returns a {} data owned by the current function", reference_desc),
+            format!("{}s a {} data owned by the current function", return_kind, reference_desc),
         );
 
         self.cancel_if_wrong_origin(err, o)
index 8a016bf87795b8b9239833ccb2b97f669de6d196..a8f7299f89937a29898d7fd31052cec7de32bf22 100644 (file)
@@ -25,7 +25,7 @@ fn next(&mut self) -> Option<Self::Item> {
 fn bug<'a>() -> impl Iterator<Item = &'a str> {
     GenIter(move || {
         let mut s = String::new();
-        yield &s[..] //~ ERROR `s` does not live long enough [E0597]
+        yield &s[..] //~ ERROR cannot yield value referencing local variable `s` [E0515]
         //~| ERROR borrow may still be in use when generator yields
     })
 }
index 66c2995efc8805e12c29a13a913bd1f63b33e38d..86a8cdc42ff9fdf1e344ae54ae628241c1a135c8 100644 (file)
@@ -1,11 +1,11 @@
-error[E0597]: `s` does not live long enough
-  --> $DIR/issue-55850.rs:28:16
+error[E0515]: cannot yield value referencing local variable `s`
+  --> $DIR/issue-55850.rs:28:9
    |
 LL |         yield &s[..]
-   |                ^ borrowed value does not live long enough
-LL |
-LL |     })
-   |     - `s` dropped here while still borrowed
+   |         ^^^^^^^-^^^^
+   |         |      |
+   |         |      `s` is borrowed here
+   |         yields a value referencing data owned by the current function
 
 error[E0626]: borrow may still be in use when generator yields
   --> $DIR/issue-55850.rs:28:16
@@ -15,5 +15,5 @@ LL |         yield &s[..]
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0597, E0626.
-For more information about an error, try `rustc --explain E0597`.
+Some errors have detailed explanations: E0515, E0626.
+For more information about an error, try `rustc --explain E0515`.