From 70ce90c320aa4d6ae7646497a0cd17f775b94e43 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Tue, 16 Aug 2016 15:02:20 -0700 Subject: [PATCH] Move 'doesn't live long enough' errors to labels --- .../borrowck/gather_loans/lifetime.rs | 2 +- src/librustc_borrowck/borrowck/mod.rs | 92 +++++++++++++++---- .../borrowck-let-suggestion-suffixes.rs | 23 ++--- .../borrowck/borrowck-let-suggestion.rs | 6 +- .../compile-fail/impl-trait/loan-extend.rs | 6 +- .../region-borrow-params-issue-29793-small.rs | 24 +++-- .../send-is-not-static-ensures-scoping.rs | 2 +- .../unboxed-closures-failed-recursive-fn-1.rs | 2 +- .../{compile-fail => ui/span}/issue-11925.rs | 2 +- src/test/ui/span/issue-11925.stderr | 14 +++ 10 files changed, 128 insertions(+), 45 deletions(-) rename src/test/{compile-fail => ui/span}/issue-11925.rs (89%) create mode 100644 src/test/ui/span/issue-11925.stderr diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index e34c6e567bd..667bf16874e 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -96,7 +96,7 @@ fn check_scope(&self, max_scope: ty::Region) -> R { //! Reports an error if `loan_region` is larger than `max_scope` if !self.bccx.is_subregion_of(self.loan_region, max_scope) { - Err(self.report_error(err_out_of_scope(max_scope, self.loan_region))) + Err(self.report_error(err_out_of_scope(max_scope, self.loan_region, self.cause))) } else { Ok(()) } diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index e0cbd972bd3..7e3466c1ad8 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -43,7 +43,7 @@ use std::rc::Rc; use syntax::ast; use syntax::attr::AttrMetaMethods; -use syntax_pos::{MultiSpan, Span}; +use syntax_pos::{MultiSpan, Span, BytePos}; use errors::DiagnosticBuilder; use rustc::hir; @@ -566,7 +566,7 @@ pub fn opt_loan_path<'tcx>(cmt: &mc::cmt<'tcx>) -> Option>> { #[derive(PartialEq)] pub enum bckerr_code { err_mutbl, - err_out_of_scope(ty::Region, ty::Region), // superscope, subscope + err_out_of_scope(ty::Region, ty::Region, euv::LoanCause), // superscope, subscope, loan cause err_borrowed_pointer_too_short(ty::Region, ty::Region), // loan, ptr } @@ -614,9 +614,9 @@ pub fn is_subregion_of(&self, r_sub: ty::Region, r_sup: ty::Region) pub fn report(&self, err: BckError<'tcx>) { // Catch and handle some particular cases. match (&err.code, &err.cause) { - (&err_out_of_scope(ty::ReScope(_), ty::ReStatic), + (&err_out_of_scope(ty::ReScope(_), ty::ReStatic, _), &BorrowViolation(euv::ClosureCapture(span))) | - (&err_out_of_scope(ty::ReScope(_), ty::ReFree(..)), + (&err_out_of_scope(ty::ReScope(_), ty::ReFree(..), _), &BorrowViolation(euv::ClosureCapture(span))) => { return self.report_out_of_scope_escaping_closure_capture(&err, span); } @@ -963,6 +963,24 @@ fn report_out_of_scope_escaping_closure_capture(&self, .emit(); } + fn convert_region_to_span(&self, region: ty::Region) -> Option { + match region { + ty::ReScope(scope) => { + match scope.span(&self.tcx.region_maps, &self.tcx.map) { + Some(s) => { + let mut last_span = s; + last_span.lo = BytePos(last_span.hi.0 - 1); + Some(last_span) + } + None => { + None + } + } + } + _ => None + } + } + pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>, error_span: Span) { let code = err.code; @@ -1003,19 +1021,61 @@ pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError< } } - err_out_of_scope(super_scope, sub_scope) => { - self.tcx.note_and_explain_region( - db, - "reference must be valid for ", - sub_scope, - "..."); - self.tcx.note_and_explain_region( - db, - "...but borrowed value is only valid for ", - super_scope, - ""); + err_out_of_scope(super_scope, sub_scope, cause) => { + match cause { + euv::ClosureCapture(s) => { + match db.span.primary_span() { + Some(primary) => { + db.span = MultiSpan::from_span(s); + db.span_label(primary, &format!("capture occurs here")); + db.span_label(s, &format!("does not live long enough")); + } + None => () + } + } + _ => { + db.span_label(error_span, &format!("does not live long enough")); + } + } + + let sub_span = self.convert_region_to_span(sub_scope); + let super_span = self.convert_region_to_span(super_scope); + + match (sub_span, super_span) { + (Some(s1), Some(s2)) if s1 == s2 => { + db.span_label(s1, &"borrowed value dropped before borrower"); + db.note("values in a scope are dropped in the opposite order \ + they are created"); + } + _ => { + match sub_span { + Some(s) => { + db.span_label(s, &"borrowed value must be valid until here"); + } + None => { + self.tcx.note_and_explain_region( + db, + "borrowed value must be valid for ", + sub_scope, + "..."); + } + } + match super_span { + Some(s) => { + db.span_label(s, &"borrowed value only valid until here"); + } + None => { + self.tcx.note_and_explain_region( + db, + "...but borrowed value is only valid for ", + super_scope, + ""); + } + } + } + } + if let Some(span) = statement_scope_span(self.tcx, super_scope) { - db.span_label(error_span, &format!("does not live long enough")); db.span_help(span, "consider using a `let` binding to increase its lifetime"); } diff --git a/src/test/compile-fail/borrowck/borrowck-let-suggestion-suffixes.rs b/src/test/compile-fail/borrowck/borrowck-let-suggestion-suffixes.rs index 02aa771c787..6c9f67b2b33 100644 --- a/src/test/compile-fail/borrowck/borrowck-let-suggestion-suffixes.rs +++ b/src/test/compile-fail/borrowck/borrowck-let-suggestion-suffixes.rs @@ -13,47 +13,48 @@ fn f() { let mut v1 = Vec::new(); // statement 1 let mut v2 = Vec::new(); // statement 2 - //~^ NOTE reference must be valid for the block suffix following statement 2 let young = ['y']; // statement 3 - //~^ NOTE ...but borrowed value is only valid for the block suffix following statement 3 v2.push(&young[0]); // statement 4 //~^ ERROR `young[..]` does not live long enough + //~| NOTE does not live long enough + //~| NOTE values in a scope are dropped in the opposite order they are created let mut v3 = Vec::new(); // statement 5 - //~^ NOTE reference must be valid for the block suffix following statement 5 v3.push(&'x'); // statement 6 //~^ ERROR borrowed value does not live long enough - //~| does not live long enough - //~| NOTE ...but borrowed value is only valid for the statement + //~| NOTE does not live long enough + //~| NOTE borrowed value only valid until here //~| HELP consider using a `let` binding to increase its lifetime { let mut v4 = Vec::new(); // (sub) statement 0 - //~^ NOTE reference must be valid for the block suffix following statement 0 v4.push(&'y'); //~^ ERROR borrowed value does not live long enough - //~| does not live long enough - //~| NOTE ...but borrowed value is only valid for the statement + //~| NOTE does not live long enough + //~| NOTE borrowed value only valid until here //~| HELP consider using a `let` binding to increase its lifetime } // (statement 7) + //~^ NOTE borrowed value must be valid until here let mut v5 = Vec::new(); // statement 8 - //~^ NOTE reference must be valid for the block suffix following statement 8 v5.push(&'z'); //~^ ERROR borrowed value does not live long enough - //~| does not live long enough - //~| NOTE ...but borrowed value is only valid for the statement + //~| NOTE does not live long enough + //~| NOTE borrowed value only valid until here //~| HELP consider using a `let` binding to increase its lifetime v1.push(&old[0]); } +//~^ NOTE borrowed value dropped before borrower +//~| NOTE borrowed value must be valid until here +//~| NOTE borrowed value must be valid until here fn main() { f(); diff --git a/src/test/compile-fail/borrowck/borrowck-let-suggestion.rs b/src/test/compile-fail/borrowck/borrowck-let-suggestion.rs index 866e72f1a52..ef8f44c1df7 100644 --- a/src/test/compile-fail/borrowck/borrowck-let-suggestion.rs +++ b/src/test/compile-fail/borrowck/borrowck-let-suggestion.rs @@ -11,11 +11,11 @@ fn f() { let x = [1].iter(); //~^ ERROR borrowed value does not live long enough - //~|does not live long enough - //~| NOTE reference must be valid for the block suffix following statement + //~| NOTE does not live long enough + //~| NOTE borrowed value only valid until here //~| HELP consider using a `let` binding to increase its lifetime - //~| NOTE ...but borrowed value is only valid for the statement at 12:4 } +//~^ borrowed value must be valid until here fn main() { f(); diff --git a/src/test/compile-fail/impl-trait/loan-extend.rs b/src/test/compile-fail/impl-trait/loan-extend.rs index ceaa8f4eed7..8dfcb08cff3 100644 --- a/src/test/compile-fail/impl-trait/loan-extend.rs +++ b/src/test/compile-fail/impl-trait/loan-extend.rs @@ -14,10 +14,10 @@ fn borrow<'a, T>(_: &'a mut T) -> impl Copy { () } fn main() { - //~^ NOTE reference must be valid for the block let long; let mut short = 0; - //~^ NOTE but borrowed value is only valid for the block suffix following statement 1 long = borrow(&mut short); //~^ ERROR `short` does not live long enough -} + //~| NOTE does not live long enough + //~| NOTE values in a scope are dropped in the opposite order they are created +} //~ borrowed value dropped before borrower diff --git a/src/test/compile-fail/region-borrow-params-issue-29793-small.rs b/src/test/compile-fail/region-borrow-params-issue-29793-small.rs index 6be2adbe2a0..196c233a0b5 100644 --- a/src/test/compile-fail/region-borrow-params-issue-29793-small.rs +++ b/src/test/compile-fail/region-borrow-params-issue-29793-small.rs @@ -16,15 +16,19 @@ fn escaping_borrow_of_closure_params_1() { let g = |x: usize, y:usize| { - //~^ NOTE reference must be valid for the scope of call-site for function - //~| NOTE ...but borrowed value is only valid for the scope of function body - //~| NOTE reference must be valid for the scope of call-site for function - //~| NOTE ...but borrowed value is only valid for the scope of function body let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) //~^ ERROR `x` does not live long enough //~| ERROR `y` does not live long enough + //~| NOTE capture occurs here + //~| NOTE capture occurs here + //~| NOTE does not live long enough + //~| NOTE does not live long enough + //~| NOTE values in a scope are dropped in the opposite order they are created + //~| NOTE values in a scope are dropped in the opposite order they are created return f; }; + //~^ NOTE borrowed value dropped before borrower + //~| NOTE borrowed value dropped before borrower // We delberately do not call `g`; this small version of the test, // after adding such a call, was (properly) rejected even when the @@ -35,15 +39,19 @@ fn escaping_borrow_of_closure_params_1() { fn escaping_borrow_of_closure_params_2() { let g = |x: usize, y:usize| { - //~^ NOTE reference must be valid for the scope of call-site for function - //~| NOTE ...but borrowed value is only valid for the scope of function body - //~| NOTE reference must be valid for the scope of call-site for function - //~| NOTE ...but borrowed value is only valid for the scope of function body let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) //~^ ERROR `x` does not live long enough //~| ERROR `y` does not live long enough + //~| NOTE capture occurs here + //~| NOTE capture occurs here + //~| NOTE does not live long enough + //~| NOTE does not live long enough + //~| NOTE values in a scope are dropped in the opposite order they are created + //~| NOTE values in a scope are dropped in the opposite order they are created f }; + //~^ NOTE borrowed value dropped before borrower + //~| NOTE borrowed value dropped before borrower // (we don't call `g`; see above) } diff --git a/src/test/compile-fail/send-is-not-static-ensures-scoping.rs b/src/test/compile-fail/send-is-not-static-ensures-scoping.rs index 2e401ba6e90..1b7718d2283 100644 --- a/src/test/compile-fail/send-is-not-static-ensures-scoping.rs +++ b/src/test/compile-fail/send-is-not-static-ensures-scoping.rs @@ -26,8 +26,8 @@ fn main() { let y = &x; //~ ERROR `x` does not live long enough scoped(|| { - //~^ ERROR `y` does not live long enough let _z = y; + //~^ ERROR `y` does not live long enough }) }; diff --git a/src/test/compile-fail/unboxed-closures-failed-recursive-fn-1.rs b/src/test/compile-fail/unboxed-closures-failed-recursive-fn-1.rs index f73b0665301..ce60521034e 100644 --- a/src/test/compile-fail/unboxed-closures-failed-recursive-fn-1.rs +++ b/src/test/compile-fail/unboxed-closures-failed-recursive-fn-1.rs @@ -22,8 +22,8 @@ fn a() { let mut factorial: Option u32>> = None; let f = |x: u32| -> u32 { - //~^ ERROR `factorial` does not live long enough let g = factorial.as_ref().unwrap(); + //~^ ERROR `factorial` does not live long enough if x == 0 {1} else {x * g(x-1)} }; diff --git a/src/test/compile-fail/issue-11925.rs b/src/test/ui/span/issue-11925.rs similarity index 89% rename from src/test/compile-fail/issue-11925.rs rename to src/test/ui/span/issue-11925.rs index 7bd072c6268..7bea8642cce 100644 --- a/src/test/compile-fail/issue-11925.rs +++ b/src/test/ui/span/issue-11925.rs @@ -15,7 +15,7 @@ fn to_fn_once>(f: F) -> F { f } fn main() { let r = { let x: Box<_> = box 42; - let f = to_fn_once(move|| &x); //~ ERROR: `x` does not live long enough + let f = to_fn_once(move|| &x); f() }; diff --git a/src/test/ui/span/issue-11925.stderr b/src/test/ui/span/issue-11925.stderr new file mode 100644 index 00000000000..d379cfc3d68 --- /dev/null +++ b/src/test/ui/span/issue-11925.stderr @@ -0,0 +1,14 @@ +error: `x` does not live long enough + --> $DIR/issue-11925.rs:18:36 + | +18 | let f = to_fn_once(move|| &x); + | ^ + | | + | does not live long enough + | borrowed value only valid until here +... +23 | } + | - borrowed value must be valid until here + +error: aborting due to previous error + -- 2.44.0