Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 32772fd

Browse files
committedJul 22, 2018
Auto merge of #52572 - davidtwco:issue-51027, r=nikomatsakis
NLL diagnostics replaced nice closure errors w/ indecipherable free region errors Fixes #51027. r? @nikomatsakis
2 parents d3b3bc5 + c64db00 commit 32772fd

19 files changed

+367
-157
lines changed
 

‎src/librustc/mir/tcx.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,39 @@ impl<'tcx> Place<'tcx> {
119119
proj.base.ty(local_decls, tcx).projection_ty(tcx, &proj.elem),
120120
}
121121
}
122+
123+
/// If this is a field projection, and the field is being projected from a closure type,
124+
/// then returns the index of the field being projected. Note that this closure will always
125+
/// be `self` in the current MIR, because that is the only time we directly access the fields
126+
/// of a closure type.
127+
pub fn is_upvar_field_projection<'cx, 'gcx>(&self, mir: &'cx Mir<'tcx>,
128+
tcx: &TyCtxt<'cx, 'gcx, 'tcx>) -> Option<Field> {
129+
let place = if let Place::Projection(ref proj) = self {
130+
if let ProjectionElem::Deref = proj.elem {
131+
&proj.base
132+
} else {
133+
self
134+
}
135+
} else {
136+
self
137+
};
138+
139+
match place {
140+
Place::Projection(ref proj) => match proj.elem {
141+
ProjectionElem::Field(field, _ty) => {
142+
let base_ty = proj.base.ty(mir, *tcx).to_ty(*tcx);
143+
144+
if base_ty.is_closure() || base_ty.is_generator() {
145+
Some(field)
146+
} else {
147+
None
148+
}
149+
},
150+
_ => None,
151+
},
152+
_ => None,
153+
}
154+
}
122155
}
123156

124157
pub enum RvalueInitializationState {

‎src/librustc_mir/borrow_check/error_reporting.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
726726
Place::Projection(ref proj) => {
727727
match proj.elem {
728728
ProjectionElem::Deref => {
729-
if let Some(field) = self.is_upvar_field_projection(&proj.base) {
729+
let upvar_field_projection = place.is_upvar_field_projection(
730+
self.mir, &self.tcx);
731+
if let Some(field) = upvar_field_projection {
730732
let var_index = field.index();
731733
let name = self.mir.upvar_decls[var_index].debug_name.to_string();
732734
if self.mir.upvar_decls[var_index].by_ref {
@@ -785,7 +787,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
785787
ProjectionElem::Field(field, _ty) => {
786788
autoderef = true;
787789

788-
if let Some(field) = self.is_upvar_field_projection(place) {
790+
let upvar_field_projection = place.is_upvar_field_projection(
791+
self.mir, &self.tcx);
792+
if let Some(field) = upvar_field_projection {
789793
let var_index = field.index();
790794
let name = self.mir.upvar_decls[var_index].debug_name.to_string();
791795
buf.push_str(&name);

‎src/librustc_mir/borrow_check/mod.rs

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,7 +1214,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
12141214
}
12151215
Operand::Move(ref place @ Place::Projection(_))
12161216
| Operand::Copy(ref place @ Place::Projection(_)) => {
1217-
if let Some(field) = self.is_upvar_field_projection(place) {
1217+
if let Some(field) = place.is_upvar_field_projection(
1218+
self.mir, &self.tcx) {
12181219
self.used_mut_upvars.push(field);
12191220
}
12201221
}
@@ -1803,7 +1804,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
18031804
place: place @ Place::Projection(_),
18041805
is_local_mutation_allowed: _,
18051806
} => {
1806-
if let Some(field) = self.is_upvar_field_projection(&place) {
1807+
if let Some(field) = place.is_upvar_field_projection(self.mir, &self.tcx) {
18071808
self.used_mut_upvars.push(field);
18081809
}
18091810
}
@@ -1866,7 +1867,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
18661867
// Mutably borrowed data is mutable, but only if we have a
18671868
// unique path to the `&mut`
18681869
hir::MutMutable => {
1869-
let mode = match self.is_upvar_field_projection(&proj.base)
1870+
let mode = match place.is_upvar_field_projection(
1871+
self.mir, &self.tcx)
18701872
{
18711873
Some(field)
18721874
if {
@@ -1911,7 +1913,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
19111913
| ProjectionElem::ConstantIndex { .. }
19121914
| ProjectionElem::Subslice { .. }
19131915
| ProjectionElem::Downcast(..) => {
1914-
if let Some(field) = self.is_upvar_field_projection(place) {
1916+
let upvar_field_projection = place.is_upvar_field_projection(
1917+
self.mir, &self.tcx);
1918+
if let Some(field) = upvar_field_projection {
19151919
let decl = &self.mir.upvar_decls[field.index()];
19161920
debug!(
19171921
"decl.mutability={:?} local_mutation_is_allowed={:?} place={:?}",
@@ -1965,28 +1969,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
19651969
}
19661970
}
19671971
}
1968-
1969-
/// If this is a field projection, and the field is being projected from a closure type,
1970-
/// then returns the index of the field being projected. Note that this closure will always
1971-
/// be `self` in the current MIR, because that is the only time we directly access the fields
1972-
/// of a closure type.
1973-
fn is_upvar_field_projection(&self, place: &Place<'tcx>) -> Option<Field> {
1974-
match *place {
1975-
Place::Projection(ref proj) => match proj.elem {
1976-
ProjectionElem::Field(field, _ty) => {
1977-
let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
1978-
1979-
if base_ty.is_closure() || base_ty.is_generator() {
1980-
Some(field)
1981-
} else {
1982-
None
1983-
}
1984-
}
1985-
_ => None,
1986-
},
1987-
_ => None,
1988-
}
1989-
}
19901972
}
19911973

19921974
#[derive(Copy, Clone, PartialEq, Eq, Debug)]

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

Lines changed: 104 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use std::fmt;
2222
use syntax_pos::Span;
2323

2424
mod region_name;
25+
mod var_name;
2526

2627
/// Constraints that are considered interesting can be categorized to
2728
/// determine why they are interesting. Order of variants indicates
@@ -30,7 +31,9 @@ mod region_name;
3031
enum ConstraintCategory {
3132
Cast,
3233
Assignment,
34+
AssignmentToUpvar,
3335
Return,
36+
CallArgumentToUpvar,
3437
CallArgument,
3538
Other,
3639
Boring,
@@ -39,10 +42,12 @@ enum ConstraintCategory {
3942
impl fmt::Display for ConstraintCategory {
4043
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4144
match self {
42-
ConstraintCategory::Assignment => write!(f, "assignment"),
45+
ConstraintCategory::Assignment |
46+
ConstraintCategory::AssignmentToUpvar => write!(f, "assignment"),
4347
ConstraintCategory::Return => write!(f, "return"),
4448
ConstraintCategory::Cast => write!(f, "cast"),
45-
ConstraintCategory::CallArgument => write!(f, "argument"),
49+
ConstraintCategory::CallArgument |
50+
ConstraintCategory::CallArgumentToUpvar => write!(f, "argument"),
4651
_ => write!(f, "free region"),
4752
}
4853
}
@@ -130,8 +135,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
130135
&self,
131136
index: ConstraintIndex,
132137
mir: &Mir<'tcx>,
138+
_infcx: &InferCtxt<'_, '_, 'tcx>,
133139
) -> (ConstraintCategory, Span) {
134140
let constraint = self.constraints[index];
141+
debug!("classify_constraint: constraint={:?}", constraint);
135142
let span = constraint.locations.span(mir);
136143
let location = constraint.locations.from_location().unwrap_or(Location::START);
137144

@@ -140,8 +147,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
140147
}
141148

142149
let data = &mir[location.block];
150+
debug!("classify_constraint: location={:?} data={:?}", location, data);
143151
let category = if location.statement_index == data.statements.len() {
144152
if let Some(ref terminator) = data.terminator {
153+
debug!("classify_constraint: terminator.kind={:?}", terminator.kind);
145154
match terminator.kind {
146155
TerminatorKind::DropAndReplace { .. } => ConstraintCategory::Assignment,
147156
TerminatorKind::Call { .. } => ConstraintCategory::CallArgument,
@@ -152,14 +161,17 @@ impl<'tcx> RegionInferenceContext<'tcx> {
152161
}
153162
} else {
154163
let statement = &data.statements[location.statement_index];
164+
debug!("classify_constraint: statement.kind={:?}", statement.kind);
155165
match statement.kind {
156166
StatementKind::Assign(ref place, ref rvalue) => {
167+
debug!("classify_constraint: place={:?} rvalue={:?}", place, rvalue);
157168
if *place == Place::Local(mir::RETURN_PLACE) {
158169
ConstraintCategory::Return
159170
} else {
160171
match rvalue {
161172
Rvalue::Cast(..) => ConstraintCategory::Cast,
162-
Rvalue::Use(..) => ConstraintCategory::Assignment,
173+
Rvalue::Use(..) |
174+
Rvalue::Aggregate(..) => ConstraintCategory::Assignment,
163175
_ => ConstraintCategory::Other,
164176
}
165177
}
@@ -208,7 +220,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
208220

209221
// Classify each of the constraints along the path.
210222
let mut categorized_path: Vec<(ConstraintCategory, Span)> = path.iter()
211-
.map(|&index| self.classify_constraint(index, mir))
223+
.map(|&index| self.classify_constraint(index, mir, infcx))
212224
.collect();
213225
debug!("report_error: categorized_path={:?}", categorized_path);
214226

@@ -218,30 +230,100 @@ impl<'tcx> RegionInferenceContext<'tcx> {
218230

219231
// Get a span
220232
let (category, span) = categorized_path.first().unwrap();
233+
234+
let category = match (
235+
category,
236+
self.universal_regions.is_local_free_region(fr),
237+
self.universal_regions.is_local_free_region(outlived_fr),
238+
) {
239+
(ConstraintCategory::Assignment, true, false) =>
240+
&ConstraintCategory::AssignmentToUpvar,
241+
(ConstraintCategory::CallArgument, true, false) =>
242+
&ConstraintCategory::CallArgumentToUpvar,
243+
(category, _, _) => category,
244+
};
245+
246+
debug!("report_error: category={:?}", category);
247+
match category {
248+
ConstraintCategory::AssignmentToUpvar |
249+
ConstraintCategory::CallArgumentToUpvar =>
250+
self.report_closure_error(mir, infcx, mir_def_id, fr, outlived_fr, category, span),
251+
_ =>
252+
self.report_general_error(mir, infcx, mir_def_id, fr, outlived_fr, category, span),
253+
}
254+
}
255+
256+
fn report_closure_error(
257+
&self,
258+
mir: &Mir<'tcx>,
259+
infcx: &InferCtxt<'_, '_, 'tcx>,
260+
mir_def_id: DefId,
261+
fr: RegionVid,
262+
outlived_fr: RegionVid,
263+
category: &ConstraintCategory,
264+
span: &Span,
265+
) {
266+
let fr_name_and_span = self.get_var_name_and_span_for_region(
267+
infcx.tcx, mir, fr);
268+
let outlived_fr_name_and_span = self.get_var_name_and_span_for_region(
269+
infcx.tcx, mir,outlived_fr);
270+
271+
if fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none() {
272+
return self.report_general_error(mir, infcx, mir_def_id, fr, outlived_fr, category,
273+
span);
274+
}
275+
276+
let diag = &mut infcx.tcx.sess.struct_span_err(
277+
*span, &format!("borrowed data escapes outside of closure"),
278+
);
279+
280+
if let Some((outlived_fr_name, outlived_fr_span)) = outlived_fr_name_and_span {
281+
if let Some(name) = outlived_fr_name {
282+
diag.span_label(
283+
outlived_fr_span,
284+
format!("`{}` is declared here, outside of the closure body", name),
285+
);
286+
}
287+
}
288+
289+
if let Some((fr_name, fr_span)) = fr_name_and_span {
290+
if let Some(name) = fr_name {
291+
diag.span_label(
292+
fr_span,
293+
format!("`{}` is a reference that is only valid in the closure body", name),
294+
);
295+
296+
diag.span_label(*span, format!("`{}` escapes the closure body here", name));
297+
}
298+
}
299+
300+
diag.emit();
301+
}
302+
303+
fn report_general_error(
304+
&self,
305+
mir: &Mir<'tcx>,
306+
infcx: &InferCtxt<'_, '_, 'tcx>,
307+
mir_def_id: DefId,
308+
fr: RegionVid,
309+
outlived_fr: RegionVid,
310+
category: &ConstraintCategory,
311+
span: &Span,
312+
) {
221313
let diag = &mut infcx.tcx.sess.struct_span_err(
222-
*span,
223-
&format!("unsatisfied lifetime constraints"), // FIXME
314+
*span, &format!("unsatisfied lifetime constraints"), // FIXME
224315
);
225316

226-
// Figure out how we can refer
227317
let counter = &mut 1;
228-
let fr_name = self.give_region_a_name(infcx.tcx, mir, mir_def_id, fr, counter, diag);
318+
let fr_name = self.give_region_a_name(
319+
infcx.tcx, mir, mir_def_id, fr, counter, diag);
229320
let outlived_fr_name = self.give_region_a_name(
230-
infcx.tcx,
231-
mir,
232-
mir_def_id,
233-
outlived_fr,
234-
counter,
235-
diag,
236-
);
321+
infcx.tcx, mir, mir_def_id, outlived_fr, counter, diag);
237322

238-
diag.span_label(
239-
*span,
240-
format!(
241-
"{} requires that `{}` must outlive `{}`",
242-
category, fr_name, outlived_fr_name,
243-
),
244-
);
323+
diag.span_label(*span, format!(
324+
"{} requires that `{}` must outlive `{}`",
325+
category, fr_name, outlived_fr_name,
326+
));
245327

246328
diag.emit();
247329
}

‎src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs

Lines changed: 12 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@ use borrow_check::nll::region_infer::RegionInferenceContext;
1212
use borrow_check::nll::ToRegionVid;
1313
use rustc::hir;
1414
use rustc::hir::def_id::DefId;
15-
use rustc::mir::{Local, Mir};
15+
use rustc::mir::Mir;
1616
use rustc::ty::subst::{Substs, UnpackedKind};
1717
use rustc::ty::{self, RegionVid, Ty, TyCtxt};
18-
use rustc_data_structures::indexed_vec::Idx;
1918
use rustc_errors::DiagnosticBuilder;
2019
use syntax::ast::Name;
2120
use syntax::symbol::keywords;
@@ -63,11 +62,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
6362
self.give_name_from_error_region(tcx, mir_def_id, fr, counter, diag)
6463
.or_else(|| {
6564
self.give_name_if_anonymous_region_appears_in_arguments(
66-
tcx, mir, mir_def_id, fr, counter, diag,
67-
)
65+
tcx, mir, mir_def_id, fr, counter, diag)
6866
})
6967
.or_else(|| {
70-
self.give_name_if_anonymous_region_appears_in_upvars(tcx, mir, fr, counter, diag)
68+
self.give_name_if_anonymous_region_appears_in_upvars(
69+
tcx, mir, fr, counter, diag)
7170
})
7271
.or_else(|| {
7372
self.give_name_if_anonymous_region_appears_in_output(tcx, mir, fr, counter, diag)
@@ -139,24 +138,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
139138
diag: &mut DiagnosticBuilder<'_>,
140139
) -> Option<InternedString> {
141140
let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
142-
let argument_index = self
143-
.universal_regions
144-
.unnormalized_input_tys
145-
.iter()
146-
.skip(implicit_inputs)
147-
.position(|arg_ty| {
148-
debug!(
149-
"give_name_if_anonymous_region_appears_in_arguments: arg_ty = {:?}",
150-
arg_ty
151-
);
152-
tcx.any_free_region_meets(arg_ty, |r| r.to_region_vid() == fr)
153-
})?;
154-
155-
debug!(
156-
"give_name_if_anonymous_region_appears_in_arguments: \
157-
found {:?} in argument {} which has type {:?}",
158-
fr, argument_index, self.universal_regions.unnormalized_input_tys[argument_index],
159-
);
141+
let argument_index = self.get_argument_index_for_region(tcx, fr)?;
160142

161143
let arg_ty =
162144
self.universal_regions.unnormalized_input_tys[implicit_inputs + argument_index];
@@ -172,10 +154,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
172154
return Some(region_name);
173155
}
174156

157+
let (_argument_name, argument_span) = self.get_argument_name_and_span_for_region(
158+
mir, argument_index);
159+
175160
let region_name = self.synthesize_region_name(counter);
176161

177-
let argument_local = Local::new(argument_index + implicit_inputs + 1);
178-
let argument_span = mir.local_decls[argument_local].source_info.span;
179162
diag.span_label(
180163
argument_span,
181164
format!("lifetime `{}` appears in this argument", region_name,),
@@ -440,42 +423,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
440423
counter: &mut usize,
441424
diag: &mut DiagnosticBuilder<'_>,
442425
) -> Option<InternedString> {
443-
let upvar_index = self
444-
.universal_regions
445-
.defining_ty
446-
.upvar_tys(tcx)
447-
.position(|upvar_ty| {
448-
debug!(
449-
"give_name_if_anonymous_region_appears_in_upvars: upvar_ty = {:?}",
450-
upvar_ty,
451-
);
452-
tcx.any_free_region_meets(&upvar_ty, |r| r.to_region_vid() == fr)
453-
})?;
454-
455-
let upvar_ty = self
456-
.universal_regions
457-
.defining_ty
458-
.upvar_tys(tcx)
459-
.nth(upvar_index);
460-
461-
debug!(
462-
"give_name_if_anonymous_region_appears_in_upvars: \
463-
found {:?} in upvar {} which has type {:?}",
464-
fr, upvar_index, upvar_ty,
465-
);
466-
426+
let upvar_index = self.get_upvar_index_for_region(tcx, fr)?;
427+
let (upvar_name, upvar_span) = self.get_upvar_name_and_span_for_region(tcx, mir,
428+
upvar_index);
467429
let region_name = self.synthesize_region_name(counter);
468430

469-
let upvar_hir_id = mir.upvar_decls[upvar_index].var_hir_id.assert_crate_local();
470-
let upvar_node_id = tcx.hir.hir_to_node_id(upvar_hir_id);
471-
let upvar_span = tcx.hir.span(upvar_node_id);
472-
let upvar_name = tcx.hir.name(upvar_node_id);
473431
diag.span_label(
474432
upvar_span,
475-
format!(
476-
"lifetime `{}` appears in the type of `{}`",
477-
region_name, upvar_name,
478-
),
433+
format!("lifetime `{}` appears in the type of `{}`", region_name, upvar_name),
479434
);
480435

481436
Some(region_name)
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// Copyright 2017 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+
use borrow_check::nll::region_infer::RegionInferenceContext;
12+
use borrow_check::nll::ToRegionVid;
13+
use rustc::mir::{Local, Mir};
14+
use rustc::ty::{RegionVid, TyCtxt};
15+
use rustc_data_structures::indexed_vec::Idx;
16+
use syntax::codemap::Span;
17+
use syntax_pos::symbol::Symbol;
18+
19+
impl<'tcx> RegionInferenceContext<'tcx> {
20+
crate fn get_var_name_and_span_for_region(
21+
&self,
22+
tcx: TyCtxt<'_, '_, 'tcx>,
23+
mir: &Mir<'tcx>,
24+
fr: RegionVid,
25+
) -> Option<(Option<Symbol>, Span)> {
26+
debug!("get_var_name_and_span_for_region(fr={:?})", fr);
27+
assert!(self.universal_regions.is_universal_region(fr));
28+
29+
debug!("get_var_name_and_span_for_region: attempting upvar");
30+
self.get_upvar_index_for_region(tcx, fr)
31+
.map(|index| {
32+
let (name, span) = self.get_upvar_name_and_span_for_region(tcx, mir, index);
33+
(Some(name), span)
34+
})
35+
.or_else(|| {
36+
debug!("get_var_name_and_span_for_region: attempting argument");
37+
self.get_argument_index_for_region(tcx, fr)
38+
.map(|index| self.get_argument_name_and_span_for_region(mir, index))
39+
})
40+
}
41+
42+
/// Search the upvars (if any) to find one that references fr. Return its index.
43+
crate fn get_upvar_index_for_region(
44+
&self,
45+
tcx: TyCtxt<'_, '_, 'tcx>,
46+
fr: RegionVid,
47+
) -> Option<usize> {
48+
let upvar_index = self
49+
.universal_regions
50+
.defining_ty
51+
.upvar_tys(tcx)
52+
.position(|upvar_ty| {
53+
debug!(
54+
"get_upvar_index_for_region: upvar_ty = {:?}",
55+
upvar_ty,
56+
);
57+
tcx.any_free_region_meets(&upvar_ty, |r| r.to_region_vid() == fr)
58+
})?;
59+
60+
let upvar_ty = self
61+
.universal_regions
62+
.defining_ty
63+
.upvar_tys(tcx)
64+
.nth(upvar_index);
65+
66+
debug!(
67+
"get_upvar_index_for_region: found {:?} in upvar {} which has type {:?}",
68+
fr, upvar_index, upvar_ty,
69+
);
70+
71+
Some(upvar_index)
72+
}
73+
74+
/// Given the index of an upvar, finds its name and the span from where it was
75+
/// declared.
76+
crate fn get_upvar_name_and_span_for_region(
77+
&self,
78+
tcx: TyCtxt<'_, '_, 'tcx>,
79+
mir: &Mir<'tcx>,
80+
upvar_index: usize,
81+
) -> (Symbol, Span) {
82+
let upvar_hir_id = mir.upvar_decls[upvar_index].var_hir_id.assert_crate_local();
83+
let upvar_node_id = tcx.hir.hir_to_node_id(upvar_hir_id);
84+
debug!("get_upvar_name_and_span_for_region: upvar_node_id={:?}", upvar_node_id);
85+
86+
let upvar_name = tcx.hir.name(upvar_node_id);
87+
let upvar_span = tcx.hir.span(upvar_node_id);
88+
debug!("get_upvar_name_and_span_for_region: upvar_name={:?} upvar_span={:?}",
89+
upvar_name, upvar_span);
90+
91+
(upvar_name, upvar_span)
92+
}
93+
94+
/// Search the argument types for one that references fr (which should be a free region).
95+
/// Returns Some(_) with the index of the input if one is found.
96+
///
97+
/// NB: In the case of a closure, the index is indexing into the signature as seen by the
98+
/// user - in particular, index 0 is not the implicit self parameter.
99+
crate fn get_argument_index_for_region(
100+
&self,
101+
tcx: TyCtxt<'_, '_, 'tcx>,
102+
fr: RegionVid,
103+
) -> Option<usize> {
104+
let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
105+
let argument_index = self
106+
.universal_regions
107+
.unnormalized_input_tys
108+
.iter()
109+
.skip(implicit_inputs)
110+
.position(|arg_ty| {
111+
debug!(
112+
"get_argument_index_for_region: arg_ty = {:?}",
113+
arg_ty
114+
);
115+
tcx.any_free_region_meets(arg_ty, |r| r.to_region_vid() == fr)
116+
})?;
117+
118+
debug!(
119+
"get_argument_index_for_region: found {:?} in argument {} which has type {:?}",
120+
fr, argument_index, self.universal_regions.unnormalized_input_tys[argument_index],
121+
);
122+
123+
Some(argument_index)
124+
}
125+
126+
/// Given the index of an argument, finds its name (if any) and the span from where it was
127+
/// declared.
128+
crate fn get_argument_name_and_span_for_region(
129+
&self,
130+
mir: &Mir<'tcx>,
131+
argument_index: usize,
132+
) -> (Option<Symbol>, Span) {
133+
let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
134+
let argument_local = Local::new(implicit_inputs + argument_index + 1);
135+
debug!("get_argument_name_and_span_for_region: argument_local={:?}", argument_local);
136+
137+
let argument_name = mir.local_decls[argument_local].name;
138+
let argument_span = mir.local_decls[argument_local].source_info.span;
139+
debug!("get_argument_name_and_span_for_region: argument_name={:?} argument_span={:?}",
140+
argument_name, argument_span);
141+
142+
(argument_name, argument_span)
143+
}
144+
145+
}

‎src/test/ui/borrowck/issue-45983.nll.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ warning: not reporting region error due to nll
44
LL | give_any(|y| x = Some(y));
55
| ^
66

7-
error: unsatisfied lifetime constraints
7+
error: borrowed data escapes outside of closure
88
--> $DIR/issue-45983.rs:17:18
99
|
1010
LL | let x = None;
11-
| - lifetime `'2` appears in the type of `x`
11+
| - `x` is declared here, outside of the closure body
1212
LL | give_any(|y| x = Some(y));
13-
| - ^^^^^^^^^^^ free region requires that `'1` must outlive `'2`
13+
| - ^^^^^^^^^^^ `y` escapes the closure body here
1414
| |
15-
| lifetime `'1` appears in this argument
15+
| `y` is a reference that is only valid in the closure body
1616

1717
error[E0594]: cannot assign to `x`, as it is not declared as mutable
1818
--> $DIR/issue-45983.rs:17:18

‎src/test/ui/borrowck/issue-7573.nll.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ warning: not reporting region error due to nll
44
LL | let mut lines_to_use: Vec<&CrateId> = Vec::new();
55
| ^
66

7-
error: unsatisfied lifetime constraints
7+
error: borrowed data escapes outside of closure
88
--> $DIR/issue-7573.rs:32:9
99
|
1010
LL | let mut lines_to_use: Vec<&CrateId> = Vec::new();
11-
| ---------------- lifetime `'2` appears in the type of `lines_to_use`
11+
| ---------------- `lines_to_use` is declared here, outside of the closure body
1212
LL | //~^ NOTE cannot infer an appropriate lifetime
1313
LL | let push_id = |installed_id: &CrateId| {
14-
| - let's call the lifetime of this reference `'1`
14+
| ------------ `installed_id` is a reference that is only valid in the closure body
1515
...
1616
LL | lines_to_use.push(installed_id);
17-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `installed_id` escapes the closure body here
1818

1919
error: aborting due to previous error
2020

‎src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ warning: not reporting region error due to nll
44
LL | with_int(|y| x = Some(y));
55
| ^
66

7-
error: unsatisfied lifetime constraints
7+
error: borrowed data escapes outside of closure
88
--> $DIR/regions-escape-bound-fn-2.rs:18:18
99
|
1010
LL | let mut x = None;
11-
| ----- lifetime `'2` appears in the type of `x`
11+
| ----- `x` is declared here, outside of the closure body
1212
LL | with_int(|y| x = Some(y));
13-
| - ^^^^^^^^^^^ free region requires that `'1` must outlive `'2`
13+
| - ^^^^^^^^^^^ `y` escapes the closure body here
1414
| |
15-
| lifetime `'1` appears in this argument
15+
| `y` is a reference that is only valid in the closure body
1616

1717
error: aborting due to previous error
1818

‎src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ warning: not reporting region error due to nll
44
LL | with_int(|y| x = Some(y));
55
| ^^^^^^^
66

7-
error: unsatisfied lifetime constraints
7+
error: borrowed data escapes outside of closure
88
--> $DIR/regions-escape-bound-fn.rs:18:18
99
|
1010
LL | let mut x: Option<&isize> = None;
11-
| ----- lifetime `'2` appears in the type of `x`
11+
| ----- `x` is declared here, outside of the closure body
1212
LL | with_int(|y| x = Some(y));
13-
| - ^^^^^^^^^^^ free region requires that `'1` must outlive `'2`
13+
| - ^^^^^^^^^^^ `y` escapes the closure body here
1414
| |
15-
| lifetime `'1` appears in this argument
15+
| `y` is a reference that is only valid in the closure body
1616

1717
error: aborting due to previous error
1818

‎src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ warning: not reporting region error due to nll
44
LL | with_int(&mut |y| x = Some(y));
55
| ^^^^^^^
66

7-
error: unsatisfied lifetime constraints
7+
error: borrowed data escapes outside of closure
88
--> $DIR/regions-escape-unboxed-closure.rs:16:23
99
|
1010
LL | let mut x: Option<&isize> = None;
11-
| ----- lifetime `'2` appears in the type of `x`
11+
| ----- `x` is declared here, outside of the closure body
1212
LL | with_int(&mut |y| x = Some(y));
13-
| - ^^^^^^^^^^^ free region requires that `'1` must outlive `'2`
13+
| - ^^^^^^^^^^^ `y` escapes the closure body here
1414
| |
15-
| lifetime `'1` appears in this argument
15+
| `y` is a reference that is only valid in the closure body
1616

1717
error: aborting due to previous error
1818

‎src/test/ui/closure-expected-type/expect-region-supply-region.nll.stderr

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,37 +22,37 @@ warning: not reporting region error due to nll
2222
LL | f = Some(x);
2323
| ^^^^^^^
2424

25-
error: unsatisfied lifetime constraints
25+
error: borrowed data escapes outside of closure
2626
--> $DIR/expect-region-supply-region.rs:28:9
2727
|
2828
LL | let mut f: Option<&u32> = None;
29-
| ----- lifetime `'2` appears in the type of `f`
29+
| ----- `f` is declared here, outside of the closure body
3030
LL | closure_expecting_bound(|x| {
31-
| - lifetime `'1` appears in this argument
31+
| - `x` is a reference that is only valid in the closure body
3232
LL | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure
33-
| ^^^^^^^^^^^ free region requires that `'1` must outlive `'2`
33+
| ^^^^^^^^^^^ `x` escapes the closure body here
3434

35-
error: unsatisfied lifetime constraints
35+
error: borrowed data escapes outside of closure
3636
--> $DIR/expect-region-supply-region.rs:38:9
3737
|
3838
LL | let mut f: Option<&u32> = None;
39-
| ----- lifetime `'2` appears in the type of `f`
39+
| ----- `f` is declared here, outside of the closure body
4040
LL | closure_expecting_bound(|x: &u32| {
41-
| - let's call the lifetime of this reference `'1`
41+
| - `x` is a reference that is only valid in the closure body
4242
LL | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure
43-
| ^^^^^^^^^^^ free region requires that `'1` must outlive `'2`
43+
| ^^^^^^^^^^^ `x` escapes the closure body here
4444

45-
error: unsatisfied lifetime constraints
45+
error: borrowed data escapes outside of closure
4646
--> $DIR/expect-region-supply-region.rs:52:9
4747
|
4848
LL | let mut f: Option<&u32> = None;
49-
| ----- lifetime `'2` appears in the type of `f`
49+
| ----- `f` is declared here, outside of the closure body
5050
...
5151
LL | closure_expecting_bound(|x: &'x u32| {
52-
| - let's call the lifetime of this reference `'1`
52+
| - `x` is a reference that is only valid in the closure body
5353
...
5454
LL | f = Some(x);
55-
| ^^^^^^^^^^^ free region requires that `'1` must outlive `'2`
55+
| ^^^^^^^^^^^ `x` escapes the closure body here
5656

5757
error: aborting due to 3 previous errors
5858

‎src/test/ui/in-band-lifetimes/impl/dyn-trait.nll.stderr

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ warning: not reporting region error due to nll
44
LL | static_val(x); //~ ERROR cannot infer
55
| ^
66

7-
error: unsatisfied lifetime constraints
7+
error: borrowed data escapes outside of closure
88
--> $DIR/dyn-trait.rs:32:5
99
|
10+
LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
11+
| - `x` is a reference that is only valid in the closure body
1012
LL | static_val(x); //~ ERROR cannot infer
11-
| ^^^^^^^^^^^^^ argument requires that `'a` must outlive `'static`
13+
| ^^^^^^^^^^^^^ `x` escapes the closure body here
1214

1315
error: aborting due to previous error
1416

‎src/test/ui/issue-16683.nll.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ warning: not reporting region error due to nll
1010
LL | self.a(); //~ ERROR cannot infer
1111
| ^
1212

13-
error: unsatisfied lifetime constraints
13+
error: borrowed data escapes outside of closure
1414
--> $DIR/issue-16683.rs:14:9
1515
|
1616
LL | fn b(&self) {
17-
| - let's call the lifetime of this reference `'1`
17+
| ----- `self` is a reference that is only valid in the closure body
1818
LL | self.a(); //~ ERROR cannot infer
19-
| ^^^^^^^^ argument requires that `'1` must outlive `'a`
19+
| ^^^^^^^^ `self` escapes the closure body here
2020

2121
error: aborting due to previous error
2222

‎src/test/ui/issue-17758.nll.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ warning: not reporting region error due to nll
1010
LL | self.foo();
1111
| ^^^
1212

13-
error: unsatisfied lifetime constraints
13+
error: borrowed data escapes outside of closure
1414
--> $DIR/issue-17758.rs:17:9
1515
|
1616
LL | fn bar(&self) {
17-
| - let's call the lifetime of this reference `'1`
17+
| ----- `self` is a reference that is only valid in the closure body
1818
LL | self.foo();
19-
| ^^^^^^^^^^ argument requires that `'1` must outlive `'a`
19+
| ^^^^^^^^^^ `self` escapes the closure body here
2020

2121
error: aborting due to previous error
2222

‎src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@ warning: not reporting region error due to nll
44
LL | foo(cell, |cell_a, cell_x| {
55
| ^^^
66

7-
error: unsatisfied lifetime constraints
7+
error: borrowed data escapes outside of closure
88
--> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:33:20
99
|
1010
LL | foo(cell, |cell_a, cell_x| {
11-
| ------ ------ lifetime `'1` appears in this argument
11+
| ------ ------ `cell_x` is a reference that is only valid in the closure body
1212
| |
13-
| lifetime `'2` appears in this argument
13+
| `cell_a` is declared here, outside of the closure body
1414
LL | //~^ WARNING not reporting region error due to nll
1515
LL | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
16-
| ^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
16+
| ^^^^^^^^^^^^ `cell_x` escapes the closure body here
1717

1818
note: No external requirements
1919
--> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:31:15

‎src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,18 @@ LL | | });
2323
= note: number of external vids: 2
2424
= note: where '_#1r: '_#0r
2525

26-
error: unsatisfied lifetime constraints
26+
error: borrowed data escapes outside of closure
2727
--> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:45:5
2828
|
29+
LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
30+
| ------ `cell_a` is a reference that is only valid in the closure body
2931
LL | / establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
3032
LL | | //~^ ERROR
3133
LL | |
3234
LL | | // Only works if 'x: 'y:
3335
LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
3436
LL | | });
35-
| |______^ argument requires that `'a` must outlive `'static`
37+
| |______^ `cell_a` escapes the closure body here
3638

3739
note: No external requirements
3840
--> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:44:1

‎src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,18 @@ LL | | });
2323
= note: number of external vids: 3
2424
= note: where '_#1r: '_#0r
2525

26-
error: unsatisfied lifetime constraints
26+
error: borrowed data escapes outside of closure
2727
--> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:48:5
2828
|
29+
LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
30+
| ------ `cell_a` is a reference that is only valid in the closure body
2931
LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
3032
LL | | //~^ ERROR
3133
LL | | // Only works if 'x: 'y:
3234
LL | | demand_y(x, y, x.get())
3335
LL | | //~^ WARNING not reporting region error due to nll
3436
LL | | });
35-
| |______^ argument requires that `'a` must outlive `'static`
37+
| |______^ `cell_a` escapes the closure body here
3638

3739
note: No external requirements
3840
--> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:47:1

‎src/test/ui/nll/issue-50716.stderr

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
error: unsatisfied lifetime constraints
1+
error: borrowed data escapes outside of closure
22
--> $DIR/issue-50716.rs:25:14
33
|
4+
LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>)
5+
| - `s` is a reference that is only valid in the closure body
6+
...
47
LL | let _x = *s; //~ ERROR
5-
| ^^ assignment requires that `'a` must outlive `'static`
8+
| ^^ `s` escapes the closure body here
69

710
error: aborting due to previous error
811

0 commit comments

Comments
 (0)
Please sign in to comment.