Skip to content

Commit 2a3969a

Browse files
committed
Use new region infer errors for explaining borrows
This gives at least some explanation for why a borrow is expected to last for a certain free region. Also: * Reports E0373: "closure may outlive the current function" with NLL. * Special cases the case of returning a reference to (or value referencing) a local variable or temporary (E0515). * Special case assigning a reference to a local variable in a closure to a captured variable.
1 parent 275432c commit 2a3969a

File tree

131 files changed

+1849
-1820
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

131 files changed

+1849
-1820
lines changed

src/librustc_mir/borrow_check/error_reporting.rs

+283-15
Large diffs are not rendered by default.

src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs

+57-21
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,35 @@
1010

1111
use borrow_check::borrow_set::BorrowData;
1212
use borrow_check::error_reporting::UseSpans;
13-
use borrow_check::nll::region_infer::Cause;
13+
use borrow_check::nll::ConstraintDescription;
14+
use borrow_check::nll::region_infer::{Cause, RegionName};
1415
use borrow_check::{Context, MirBorrowckCtxt, WriteKind};
15-
use rustc::ty::{self, Region, TyCtxt};
16+
use rustc::ty::{self, TyCtxt};
1617
use rustc::mir::{
17-
CastKind, FakeReadCause, Local, Location, Mir, Operand, Place, Projection, ProjectionElem,
18-
Rvalue, Statement, StatementKind, TerminatorKind
18+
CastKind, ConstraintCategory, FakeReadCause, Local, Location, Mir, Operand,
19+
Place, Projection, ProjectionElem, Rvalue, Statement, StatementKind,
20+
TerminatorKind
1921
};
2022
use rustc_errors::DiagnosticBuilder;
2123
use syntax_pos::Span;
2224

2325
mod find_use;
2426

25-
pub(in borrow_check) enum BorrowExplanation<'tcx> {
27+
pub(in borrow_check) enum BorrowExplanation {
2628
UsedLater(LaterUseKind, Span),
2729
UsedLaterInLoop(LaterUseKind, Span),
2830
UsedLaterWhenDropped {
2931
drop_loc: Location,
3032
dropped_local: Local,
3133
should_note_order: bool,
3234
},
33-
MustBeValidFor(Region<'tcx>),
35+
MustBeValidFor {
36+
category: ConstraintCategory,
37+
from_closure: bool,
38+
span: Span,
39+
region_name: RegionName,
40+
opt_place_desc: Option<String>,
41+
},
3442
Unexplained,
3543
}
3644

@@ -43,8 +51,8 @@ pub(in borrow_check) enum LaterUseKind {
4351
Other,
4452
}
4553

46-
impl<'tcx> BorrowExplanation<'tcx> {
47-
pub(in borrow_check) fn add_explanation_to_diagnostic<'cx, 'gcx>(
54+
impl BorrowExplanation {
55+
pub(in borrow_check) fn add_explanation_to_diagnostic<'cx, 'gcx, 'tcx>(
4856
&self,
4957
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
5058
mir: &Mir<'tcx>,
@@ -142,15 +150,27 @@ impl<'tcx> BorrowExplanation<'tcx> {
142150
}
143151
}
144152
}
145-
}
146-
147-
BorrowExplanation::MustBeValidFor(region) => {
148-
tcx.note_and_explain_free_region(
149-
err,
150-
&format!("{}{}", borrow_desc, "borrowed value must be valid for "),
151-
region,
152-
"...",
153-
);
153+
},
154+
BorrowExplanation::MustBeValidFor {
155+
category,
156+
span,
157+
ref region_name,
158+
ref opt_place_desc,
159+
from_closure: _,
160+
} => {
161+
region_name.highlight_region_name(err);
162+
163+
if let Some(desc) = opt_place_desc {
164+
err.span_label(span, format!(
165+
"{}requires that `{}` is borrowed for `{}`",
166+
category.description(), desc, region_name,
167+
));
168+
} else {
169+
err.span_label(span, format!(
170+
"{}requires that {}borrow lasts for `{}`",
171+
category.description(), borrow_desc, region_name,
172+
));
173+
};
154174
},
155175
_ => {},
156176
}
@@ -176,7 +196,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
176196
context: Context,
177197
borrow: &BorrowData<'tcx>,
178198
kind_place: Option<(WriteKind, &Place<'tcx>)>,
179-
) -> BorrowExplanation<'tcx> {
199+
) -> BorrowExplanation {
180200
debug!(
181201
"explain_why_borrow_contains_point(context={:?}, borrow={:?}, kind_place={:?})",
182202
context, borrow, kind_place
@@ -241,11 +261,27 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
241261
}
242262
}
243263

244-
None => if let Some(region) = regioncx.to_error_region(region_sub) {
245-
BorrowExplanation::MustBeValidFor(region)
264+
None => if let Some(region) = regioncx.to_error_region_vid(borrow_region_vid) {
265+
let (category, from_closure, span, region_name) = self
266+
.nonlexical_regioncx
267+
.free_region_constraint_info(
268+
self.mir,
269+
self.mir_def_id,
270+
self.infcx,
271+
borrow_region_vid,
272+
region,
273+
);
274+
let opt_place_desc = self.describe_place(&borrow.borrowed_place);
275+
BorrowExplanation::MustBeValidFor {
276+
category,
277+
from_closure,
278+
span,
279+
region_name,
280+
opt_place_desc,
281+
}
246282
} else {
247283
BorrowExplanation::Unexplained
248-
},
284+
}
249285
}
250286
}
251287

src/librustc_mir/borrow_check/nll/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -371,3 +371,7 @@ impl ToRegionVid for RegionVid {
371371
self
372372
}
373373
}
374+
375+
crate trait ConstraintDescription {
376+
fn description(&self) -> &'static str;
377+
}

src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs

+33-20
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use borrow_check::nll::ConstraintDescription;
1112
use borrow_check::nll::constraints::{OutlivesConstraint};
1213
use borrow_check::nll::region_infer::RegionInferenceContext;
13-
use borrow_check::nll::region_infer::error_reporting::region_name::RegionNameSource;
1414
use borrow_check::nll::type_check::Locations;
1515
use borrow_check::nll::universal_regions::DefiningTy;
1616
use util::borrowck_errors::{BorrowckErrors, Origin};
@@ -29,11 +29,7 @@ use syntax::errors::Applicability;
2929
mod region_name;
3030
mod var_name;
3131

32-
use self::region_name::RegionName;
33-
34-
trait ConstraintDescription {
35-
fn description(&self) -> &'static str;
36-
}
32+
crate use self::region_name::{RegionName, RegionNameSource};
3733

3834
impl ConstraintDescription for ConstraintCategory {
3935
fn description(&self) -> &'static str {
@@ -76,7 +72,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
7672
mir: &Mir<'tcx>,
7773
from_region: RegionVid,
7874
target_test: impl Fn(RegionVid) -> bool,
79-
) -> (ConstraintCategory, Span, RegionVid) {
75+
) -> (ConstraintCategory, bool, Span) {
8076
debug!("best_blame_constraint(from_region={:?})", from_region);
8177

8278
// Find all paths
@@ -96,13 +92,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
9692
);
9793

9894
// Classify each of the constraints along the path.
99-
let mut categorized_path: Vec<(ConstraintCategory, Span)> = path
95+
let mut categorized_path: Vec<(ConstraintCategory, bool, Span)> = path
10096
.iter()
10197
.map(|constraint| {
10298
if constraint.category == ConstraintCategory::ClosureBounds {
10399
self.retrieve_closure_constraint_info(mir, &constraint)
104100
} else {
105-
(constraint.category, constraint.locations.span(mir))
101+
(constraint.category, false, constraint.locations.span(mir))
106102
}
107103
})
108104
.collect();
@@ -147,20 +143,17 @@ impl<'tcx> RegionInferenceContext<'tcx> {
147143
}
148144
});
149145
if let Some(i) = best_choice {
150-
let (category, span) = categorized_path[i];
151-
return (category, span, target_region);
146+
return categorized_path[i]
152147
}
153148

154149
// If that search fails, that is.. unusual. Maybe everything
155150
// is in the same SCC or something. In that case, find what
156151
// appears to be the most interesting point to report to the
157152
// user via an even more ad-hoc guess.
158153
categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
159-
debug!("best_blame_constraint: sorted_path={:#?}", categorized_path);
154+
debug!("`: sorted_path={:#?}", categorized_path);
160155

161-
let &(category, span) = categorized_path.first().unwrap();
162-
163-
(category, span, target_region)
156+
*categorized_path.first().unwrap()
164157
}
165158

166159
/// Walks the graph of constraints (where `'a: 'b` is considered
@@ -247,7 +240,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
247240
) {
248241
debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
249242

250-
let (category, span, _) = self.best_blame_constraint(
243+
let (category, _, span) = self.best_blame_constraint(
251244
mir,
252245
fr,
253246
|r| r == outlived_fr
@@ -580,6 +573,24 @@ impl<'tcx> RegionInferenceContext<'tcx> {
580573
}
581574
}
582575

576+
crate fn free_region_constraint_info(
577+
&self,
578+
mir: &Mir<'tcx>,
579+
mir_def_id: DefId,
580+
infcx: &InferCtxt<'_, '_, 'tcx>,
581+
borrow_region: RegionVid,
582+
outlived_region: RegionVid,
583+
) -> (ConstraintCategory, bool, Span, RegionName) {
584+
let (category, from_closure, span) = self.best_blame_constraint(
585+
mir,
586+
borrow_region,
587+
|r| r == outlived_region
588+
);
589+
let outlived_fr_name = self.give_region_a_name(
590+
infcx, mir, mir_def_id, outlived_region, &mut 1);
591+
(category, from_closure, span, outlived_fr_name)
592+
}
593+
583594
// Finds some region R such that `fr1: R` and `R` is live at
584595
// `elem`.
585596
crate fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid {
@@ -598,24 +609,26 @@ impl<'tcx> RegionInferenceContext<'tcx> {
598609
fr1: RegionVid,
599610
fr2: RegionVid,
600611
) -> (ConstraintCategory, Span) {
601-
let (category, span, _) = self.best_blame_constraint(mir, fr1, |r| r == fr2);
612+
let (category, _, span) = self.best_blame_constraint(mir, fr1, |r| r == fr2);
602613
(category, span)
603614
}
604615

605616
fn retrieve_closure_constraint_info(
606617
&self,
607618
mir: &Mir<'tcx>,
608619
constraint: &OutlivesConstraint
609-
) -> (ConstraintCategory, Span) {
620+
) -> (ConstraintCategory, bool, Span) {
610621
let loc = match constraint.locations {
611-
Locations::All(span) => return (constraint.category, span),
622+
Locations::All(span) => return (constraint.category, false, span),
612623
Locations::Single(loc) => loc,
613624
};
614625

615626
let opt_span_category = self
616627
.closure_bounds_mapping[&loc]
617628
.get(&(constraint.sup, constraint.sub));
618-
*opt_span_category.unwrap_or(&(constraint.category, mir.source_info(loc).span))
629+
opt_span_category
630+
.map(|&(category, span)| (category, true, span))
631+
.unwrap_or((constraint.category, false, mir.source_info(loc).span))
619632
}
620633

621634
/// Returns `true` if a closure is inferred to be an `FnMut` closure.

src/librustc_mir/borrow_check/nll/region_infer/mod.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use std::rc::Rc;
3535

3636
mod dump_mir;
3737
mod error_reporting;
38+
crate use self::error_reporting::{RegionName, RegionNameSource};
3839
mod graphviz;
3940
pub mod values;
4041
use self::values::{LivenessValues, RegionValueElements, RegionValues};
@@ -669,13 +670,19 @@ impl<'tcx> RegionInferenceContext<'tcx> {
669670
/// to find a good name from that. Returns `None` if we can't find
670671
/// one (e.g., this is just some random part of the CFG).
671672
pub fn to_error_region(&self, r: RegionVid) -> Option<ty::Region<'tcx>> {
673+
self.to_error_region_vid(r).and_then(|r| self.definitions[r].external_name)
674+
}
675+
676+
/// Returns the [RegionVid] corresponding to the region returned by
677+
/// `to_error_region`.
678+
pub fn to_error_region_vid(&self, r: RegionVid) -> Option<RegionVid> {
672679
if self.universal_regions.is_universal_region(r) {
673-
return self.definitions[r].external_name;
680+
Some(r)
674681
} else {
675682
let r_scc = self.constraint_sccs.scc(r);
676683
let upper_bound = self.universal_upper_bound(r);
677684
if self.scc_values.contains(r_scc, upper_bound) {
678-
self.to_error_region(upper_bound)
685+
self.to_error_region_vid(upper_bound)
679686
} else {
680687
None
681688
}

src/librustc_mir/diagnostics.rs

+40
Original file line numberDiff line numberDiff line change
@@ -2011,6 +2011,46 @@ match 5u32 {
20112011
```
20122012
"##,
20132013

2014+
E0515: r##"
2015+
Cannot return value that references local variable
2016+
2017+
Local variables, function parameters and temporaries are all dropped before the
2018+
end of the function body. So a reference to them cannot be returned.
2019+
2020+
```compile_fail,E0515
2021+
#![feature(nll)]
2022+
fn get_dangling_reference() -> &'static i32 {
2023+
let x = 0;
2024+
&x
2025+
}
2026+
```
2027+
2028+
```compile_fail,E0515
2029+
#![feature(nll)]
2030+
use std::slice::Iter;
2031+
fn get_dangling_iterator<'a>() -> Iter<'a, i32> {
2032+
let v = vec![1, 2, 3];
2033+
v.iter()
2034+
}
2035+
```
2036+
2037+
Consider returning an owned value instead:
2038+
2039+
```
2040+
use std::vec::IntoIter;
2041+
2042+
fn get_integer() -> i32 {
2043+
let x = 0;
2044+
x
2045+
}
2046+
2047+
fn get_owned_iterator() -> IntoIter<i32> {
2048+
let v = vec![1, 2, 3];
2049+
v.into_iter()
2050+
}
2051+
```
2052+
"##,
2053+
20142054
E0595: r##"
20152055
Closures cannot mutate immutable captured variables.
20162056

src/librustc_mir/util/borrowck_errors.rs

+25
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,31 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
632632
self.cancel_if_wrong_origin(err, o)
633633
}
634634

635+
fn cannot_return_reference_to_local(
636+
self,
637+
span: Span,
638+
reference_desc: &str,
639+
path_desc: &str,
640+
o: Origin,
641+
) -> DiagnosticBuilder<'cx> {
642+
let mut err = struct_span_err!(
643+
self,
644+
span,
645+
E0515,
646+
"cannot return {REFERENCE} {LOCAL}{OGN}",
647+
REFERENCE=reference_desc,
648+
LOCAL=path_desc,
649+
OGN = o
650+
);
651+
652+
err.span_label(
653+
span,
654+
format!("returns a {} data owned by the current function", reference_desc),
655+
);
656+
657+
self.cancel_if_wrong_origin(err, o)
658+
}
659+
635660
fn lifetime_too_short_for_reborrow(
636661
self,
637662
span: Span,

0 commit comments

Comments
 (0)