Skip to content

Commit 1c4532f

Browse files
committed
Improve error message where a closure escapes fn while trying to borrow
from the current fn. Employ the new `span_suggestion` to show how you can use `move`.
1 parent 0fed0c6 commit 1c4532f

File tree

3 files changed

+74
-9
lines changed

3 files changed

+74
-9
lines changed

src/librustc_borrowck/borrowck/mod.rs

+53-9
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,16 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
522522
}
523523

524524
pub fn report(&self, err: BckError<'tcx>) {
525+
// Catch and handle some particular cases.
526+
match (&err.code, &err.cause) {
527+
(&err_out_of_scope(ty::ReScope(_), ty::ReStatic), &euv::ClosureCapture(span)) |
528+
(&err_out_of_scope(ty::ReScope(_), ty::ReFree(..)), &euv::ClosureCapture(span)) => {
529+
return self.report_out_of_scope_escaping_closure_capture(&err, span);
530+
}
531+
_ => { }
532+
}
533+
534+
// General fallback.
525535
self.span_err(
526536
err.span,
527537
&self.bckerr_to_string(&err));
@@ -795,16 +805,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
795805
format!("{} does not live long enough", msg)
796806
}
797807
err_borrowed_pointer_too_short(..) => {
798-
let descr = match opt_loan_path(&err.cmt) {
799-
Some(lp) => {
800-
format!("`{}`", self.loan_path_to_string(&*lp))
801-
}
802-
None => self.cmt_to_string(&*err.cmt),
803-
};
804-
808+
let descr = self.cmt_to_path_or_string(&err.cmt);
805809
format!("lifetime of {} is too short to guarantee \
806-
its contents can be safely reborrowed",
807-
descr)
810+
its contents can be safely reborrowed",
811+
descr)
808812
}
809813
}
810814
}
@@ -886,6 +890,39 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
886890
}
887891
}
888892

893+
fn report_out_of_scope_escaping_closure_capture(&self,
894+
err: &BckError<'tcx>,
895+
capture_span: Span)
896+
{
897+
let cmt_path_or_string = self.cmt_to_path_or_string(&err.cmt);
898+
899+
span_err!(
900+
self.tcx.sess, err.span, E0371,
901+
"closure may outlive the current function, \
902+
but it borrows {}, \
903+
which is owned by the current function",
904+
cmt_path_or_string);
905+
906+
self.tcx.sess.span_note(
907+
capture_span,
908+
&format!("{} is borrowed here",
909+
cmt_path_or_string));
910+
911+
let suggestion =
912+
match self.tcx.sess.codemap().span_to_snippet(err.span) {
913+
Ok(string) => format!("move {}", string.lines().next().unwrap()),
914+
Err(_) => format!("move |<args>| <body>")
915+
};
916+
917+
self.tcx.sess.span_suggestion(
918+
err.span,
919+
&format!("to force the closure to take ownership of {} \
920+
(and any other referenced variables), \
921+
use the `move` keyword, as shown:",
922+
cmt_path_or_string),
923+
suggestion);
924+
}
925+
889926
pub fn note_and_explain_bckerr(&self, err: BckError<'tcx>) {
890927
let code = err.code;
891928
match code {
@@ -1033,6 +1070,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
10331070
pub fn cmt_to_string(&self, cmt: &mc::cmt_<'tcx>) -> String {
10341071
cmt.descriptive_string(self.tcx)
10351072
}
1073+
1074+
pub fn cmt_to_path_or_string(&self, cmt: &mc::cmt<'tcx>) -> String {
1075+
match opt_loan_path(cmt) {
1076+
Some(lp) => format!("`{}`", self.loan_path_to_string(&lp)),
1077+
None => self.cmt_to_string(cmt),
1078+
}
1079+
}
10361080
}
10371081

10381082
fn is_statement_scope(tcx: &ty::ctxt, region: ty::Region) -> bool {

src/librustc_borrowck/diagnostics.rs

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(non_snake_case)]
12+
13+
register_diagnostics! {
14+
E0371 // closure may outlive current fn, but it borrows {}, which is owned by current fn
15+
}
16+
17+
__build_diagnostic_array! { DIAGNOSTICS }

src/librustc_borrowck/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ pub use borrowck::check_crate;
4040
pub use borrowck::build_borrowck_dataflow_data_for_fn;
4141
pub use borrowck::FnPartsWithCFG;
4242

43+
// NB: This module needs to be declared first so diagnostics are
44+
// registered before they are used.
45+
pub mod diagnostics;
46+
4347
mod borrowck;
4448

4549
pub mod graphviz;

0 commit comments

Comments
 (0)