Skip to content

Commit 052d24e

Browse files
committed
Auto merge of #54088 - matthewjasper:use-reason-in-dlle-errors, r=pnkfelix
[NLL] Suggest let binding Closes #49821 Also adds an alternative to `explain_why_borrow_contains_point` that allows changing error messages based on the reason that will be given. This will also be useful for #51026, #51169 and maybe further changes to does not live long enough messages.
2 parents 85da245 + 54f7311 commit 052d24e

15 files changed

+133
-32
lines changed

src/librustc_mir/borrow_check/error_reporting.rs

+22-10
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use super::borrow_set::BorrowData;
2424
use super::{Context, MirBorrowckCtxt};
2525
use super::{InitializationRequiringAction, PrefixSet};
2626

27+
use borrow_check::nll::explain_borrow::BorrowContainsPointReason;
2728
use dataflow::drop_flag_effects;
2829
use dataflow::move_paths::indexes::MoveOutIndex;
2930
use dataflow::move_paths::MovePathIndex;
@@ -409,6 +410,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
409410
self.access_place_error_reported
410411
.insert((root_place.clone(), borrow_span));
411412

413+
let borrow_reason = self.find_why_borrow_contains_point(context, borrow);
414+
412415
let mut err = match &self.describe_place(&borrow.borrowed_place) {
413416
Some(_) if self.is_place_thread_local(root_place) => {
414417
self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span)
@@ -418,17 +421,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
418421
name,
419422
&scope_tree,
420423
&borrow,
424+
borrow_reason,
421425
drop_span,
422426
borrow_span,
423-
proper_span,
424427
kind.map(|k| (k, place_span.0)),
425428
),
426429
None => self.report_temporary_value_does_not_live_long_enough(
427430
context,
428431
&scope_tree,
429432
&borrow,
433+
borrow_reason,
430434
drop_span,
431-
borrow_span,
432435
proper_span,
433436
),
434437
};
@@ -444,16 +447,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
444447
name: &String,
445448
scope_tree: &Lrc<ScopeTree>,
446449
borrow: &BorrowData<'tcx>,
450+
reason: BorrowContainsPointReason<'tcx>,
447451
drop_span: Span,
448452
borrow_span: Span,
449-
_proper_span: Span,
450453
kind_place: Option<(WriteKind, &Place<'tcx>)>,
451454
) -> DiagnosticBuilder<'cx> {
452455
debug!(
453456
"report_local_value_does_not_live_long_enough(\
454-
{:?}, {:?}, {:?}, {:?}, {:?}, {:?}\
457+
{:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}\
455458
)",
456-
context, name, scope_tree, borrow, drop_span, borrow_span
459+
context, name, scope_tree, borrow, reason, drop_span, borrow_span
457460
);
458461

459462
let mut err = self.tcx.path_does_not_live_long_enough(
@@ -468,7 +471,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
468471
format!("`{}` dropped here while still borrowed", name),
469472
);
470473

471-
self.explain_why_borrow_contains_point(context, borrow, kind_place, &mut err);
474+
self.report_why_borrow_contains_point(&mut err, reason, kind_place);
472475
err
473476
}
474477

@@ -501,15 +504,15 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
501504
context: Context,
502505
scope_tree: &Lrc<ScopeTree>,
503506
borrow: &BorrowData<'tcx>,
507+
reason: BorrowContainsPointReason<'tcx>,
504508
drop_span: Span,
505-
_borrow_span: Span,
506509
proper_span: Span,
507510
) -> DiagnosticBuilder<'cx> {
508511
debug!(
509512
"report_temporary_value_does_not_live_long_enough(\
510-
{:?}, {:?}, {:?}, {:?}, {:?}\
513+
{:?}, {:?}, {:?}, {:?}, {:?}, {:?}\
511514
)",
512-
context, scope_tree, borrow, drop_span, proper_span
515+
context, scope_tree, borrow, reason, drop_span, proper_span
513516
);
514517

515518
let tcx = self.tcx;
@@ -518,7 +521,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
518521
err.span_label(proper_span, "temporary value does not live long enough");
519522
err.span_label(drop_span, "temporary value only lives until here");
520523

521-
self.explain_why_borrow_contains_point(context, borrow, None, &mut err);
524+
// Only give this note and suggestion if they could be relevant
525+
match reason {
526+
BorrowContainsPointReason::Liveness {..}
527+
| BorrowContainsPointReason::DropLiveness {..} => {
528+
err.note("consider using a `let` binding to create a longer lived value");
529+
}
530+
BorrowContainsPointReason::OutlivesFreeRegion {..} => (),
531+
}
532+
533+
self.report_why_borrow_contains_point(&mut err, reason, None);
522534
err
523535
}
524536

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

+86-22
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,28 @@
1111
use borrow_check::borrow_set::BorrowData;
1212
use borrow_check::nll::region_infer::Cause;
1313
use borrow_check::{Context, MirBorrowckCtxt, WriteKind};
14-
use rustc::mir::{Location, Place, TerminatorKind};
14+
use rustc::mir::{Local, Location, Place, TerminatorKind};
1515
use rustc_errors::DiagnosticBuilder;
16+
use rustc::ty::Region;
1617

1718
mod find_use;
1819

20+
#[derive(Copy, Clone, Debug)]
21+
pub enum BorrowContainsPointReason<'tcx> {
22+
Liveness {
23+
local: Local,
24+
location: Location,
25+
in_loop: bool,
26+
},
27+
DropLiveness {
28+
local: Local,
29+
location: Location,
30+
},
31+
OutlivesFreeRegion {
32+
outlived_region: Option<Region<'tcx>>,
33+
},
34+
}
35+
1936
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
2037
/// Adds annotations to `err` explaining *why* the borrow contains the
2138
/// point from `context`. This is key for the "3-point errors"
@@ -32,15 +49,30 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
3249
///
3350
/// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
3451
pub(in borrow_check) fn explain_why_borrow_contains_point(
35-
&mut self,
52+
&self,
3653
context: Context,
3754
borrow: &BorrowData<'tcx>,
3855
kind_place: Option<(WriteKind, &Place<'tcx>)>,
3956
err: &mut DiagnosticBuilder<'_>,
4057
) {
58+
let reason = self.find_why_borrow_contains_point(context, borrow);
59+
self.report_why_borrow_contains_point(err, reason, kind_place);
60+
}
61+
62+
/// Finds the reason that [explain_why_borrow_contains_point] will report
63+
/// but doesn't add it to any message. This is a separate function in case
64+
/// the caller wants to change the error they report based on the reason
65+
/// that will be reported.
66+
pub(in borrow_check) fn find_why_borrow_contains_point(
67+
&self,
68+
context: Context,
69+
borrow: &BorrowData<'tcx>
70+
) -> BorrowContainsPointReason<'tcx> {
71+
use self::BorrowContainsPointReason::*;
72+
4173
debug!(
42-
"explain_why_borrow_contains_point(context={:?}, borrow={:?}, kind_place={:?})",
43-
context, borrow, kind_place,
74+
"find_why_borrow_contains_point(context={:?}, borrow={:?})",
75+
context, borrow,
4476
);
4577

4678
let regioncx = &self.nonlexical_regioncx;
@@ -62,11 +94,45 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
6294
);
6395

6496
match find_use::find(mir, regioncx, tcx, region_sub, context.loc) {
65-
Some(Cause::LiveVar(local, location)) => {
97+
Some(Cause::LiveVar(local, location)) => Liveness {
98+
local,
99+
location,
100+
in_loop: self.is_borrow_location_in_loop(context.loc),
101+
},
102+
Some(Cause::DropVar(local, location)) => DropLiveness {
103+
local,
104+
location,
105+
},
106+
None => OutlivesFreeRegion {
107+
outlived_region: regioncx.to_error_region(region_sub),
108+
},
109+
}
110+
}
111+
112+
/// Adds annotations to `err` for the explanation `reason`. This is a
113+
/// separate method so that the caller can change their error message based
114+
/// on the reason that is going to be reported.
115+
pub (in borrow_check) fn report_why_borrow_contains_point(
116+
&self,
117+
err: &mut DiagnosticBuilder,
118+
reason: BorrowContainsPointReason<'tcx>,
119+
kind_place: Option<(WriteKind, &Place<'tcx>)>,
120+
) {
121+
use self::BorrowContainsPointReason::*;
122+
123+
debug!(
124+
"find_why_borrow_contains_point(reason={:?}, kind_place={:?})",
125+
reason, kind_place,
126+
);
127+
128+
let mir = self.mir;
129+
130+
match reason {
131+
Liveness { local, location, in_loop } => {
66132
let span = mir.source_info(location).span;
67133
let spans = self.move_spans(&Place::Local(local), location)
68134
.or_else(|| self.borrow_spans(span, location));
69-
let message = if self.is_borrow_location_in_loop(context.loc) {
135+
let message = if in_loop {
70136
if spans.for_closure() {
71137
"borrow captured here by closure in later iteration of loop"
72138
} else {
@@ -81,8 +147,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
81147
};
82148
err.span_label(spans.var_or_use(), message);
83149
}
84-
85-
Some(Cause::DropVar(local, location)) => match &mir.local_decls[local].name {
150+
DropLiveness { local, location } => match &mir.local_decls[local].name {
86151
Some(local_name) => {
87152
err.span_label(
88153
mir.source_info(location).span,
@@ -93,31 +158,29 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
93158
if let Place::Local(borrowed_local) = place {
94159
let dropped_local_scope = mir.local_decls[local].visibility_scope;
95160
let borrowed_local_scope =
96-
mir.local_decls[*borrowed_local].visibility_scope;
161+
mir.local_decls[*borrowed_local].visibility_scope;
97162

98163
if mir.is_sub_scope(borrowed_local_scope, dropped_local_scope) {
99164
err.note(
100-
"values in a scope are dropped \
101-
in the opposite order they are defined",
165+
"values in a scope are dropped \
166+
in the opposite order they are defined",
102167
);
103168
}
104169
}
105170
}
106171
}
107172

108173
None => {}
109-
},
110-
111-
None => {
112-
if let Some(region) = regioncx.to_error_region(region_sub) {
113-
self.tcx.note_and_explain_free_region(
114-
err,
115-
"borrowed value must be valid for ",
116-
region,
117-
"...",
118-
);
119-
}
120174
}
175+
OutlivesFreeRegion { outlived_region: Some(region) } => {
176+
self.tcx.note_and_explain_free_region(
177+
err,
178+
"borrowed value must be valid for ",
179+
region,
180+
"...",
181+
);
182+
}
183+
OutlivesFreeRegion { outlived_region: None } => (),
121184
}
122185
}
123186

@@ -193,3 +256,4 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
193256
false
194257
}
195258
}
259+

src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.nll.stderr

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ LL | let x = defer(&vec!["Goodbye", "world!"]);
88
LL | x.x[0];
99
| ------ borrow later used here
1010
|
11+
= note: consider using a `let` binding to create a longer lived value
1112
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
1213

1314
error: aborting due to previous error

src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.nll.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ LL | buggy_map.insert(42, &*Box::new(1)); //~ ERROR borrowed value does not
88
...
99
LL | buggy_map.insert(43, &*tmp);
1010
| --------- borrow later used here
11+
|
12+
= note: consider using a `let` binding to create a longer lived value
1113

1214
error: aborting due to previous error
1315

src/test/ui/issues/issue-36082.ast.nll.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ LL | let val: &_ = x.borrow().0;
88
...
99
LL | println!("{}", val);
1010
| --- borrow later used here
11+
|
12+
= note: consider using a `let` binding to create a longer lived value
1113

1214
error: aborting due to previous error
1315

src/test/ui/issues/issue-36082.mir.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ LL | let val: &_ = x.borrow().0;
88
...
99
LL | println!("{}", val);
1010
| --- borrow later used here
11+
|
12+
= note: consider using a `let` binding to create a longer lived value
1113

1214
error: aborting due to previous error
1315

src/test/ui/issues/issue-36082.rs

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ fn main() {
2828
//[mir]~^^^^^ ERROR borrowed value does not live long enough [E0597]
2929
//[mir]~| NOTE temporary value does not live long enough
3030
//[mir]~| NOTE temporary value only lives until here
31+
//[mir]~| NOTE consider using a `let` binding to create a longer lived value
3132
println!("{}", val);
3233
//[mir]~^ borrow later used here
3334
}

src/test/ui/lifetimes/borrowck-let-suggestion.nll.stderr

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ LL | //~^ ERROR borrowed value does not live long enough
99
LL | x.use_mut();
1010
| - borrow later used here
1111
|
12+
= note: consider using a `let` binding to create a longer lived value
1213
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
1314

1415
error: aborting due to previous error

src/test/ui/nll/borrowed-temporary-error.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ LL | });
88
| - temporary value only lives until here
99
LL | println!("{:?}", x);
1010
| - borrow later used here
11+
|
12+
= note: consider using a `let` binding to create a longer lived value
1113

1214
error: aborting due to previous error
1315

src/test/ui/regions/regions-var-type-out-of-scope.nll.stderr

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ LL | x = &id(3); //~ ERROR borrowed value does not live long enough
88
LL | assert_eq!(*x, 3);
99
| ------------------ borrow later used here
1010
|
11+
= note: consider using a `let` binding to create a longer lived value
1112
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
1213

1314
error: aborting due to previous error

src/test/ui/span/borrowck-let-suggestion-suffixes.nll.stderr

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ LL | v3.push(&id('x')); // statement 6
88
...
99
LL | (v1, v2, v3, /* v4 is above. */ v5).use_ref();
1010
| -- borrow later used here
11+
|
12+
= note: consider using a `let` binding to create a longer lived value
1113

1214
error[E0597]: borrowed value does not live long enough
1315
--> $DIR/borrowck-let-suggestion-suffixes.rs:38:18
@@ -19,6 +21,8 @@ LL | v4.push(&id('y'));
1921
...
2022
LL | v4.use_ref();
2123
| -- borrow later used here
24+
|
25+
= note: consider using a `let` binding to create a longer lived value
2226

2327
error[E0597]: borrowed value does not live long enough
2428
--> $DIR/borrowck-let-suggestion-suffixes.rs:49:14
@@ -30,6 +34,8 @@ LL | v5.push(&id('z'));
3034
...
3135
LL | (v1, v2, v3, /* v4 is above. */ v5).use_ref();
3236
| -- borrow later used here
37+
|
38+
= note: consider using a `let` binding to create a longer lived value
3339

3440
error: aborting due to 3 previous errors
3541

src/test/ui/span/borrowck-ref-into-rvalue.nll.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ LL | }
88
| - temporary value only lives until here
99
LL | println!("{}", *msg);
1010
| ---- borrow later used here
11+
|
12+
= note: consider using a `let` binding to create a longer lived value
1113

1214
error: aborting due to previous error
1315

src/test/ui/span/issue-15480.nll.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ LL | ];
88
...
99
LL | for &&x in &v {
1010
| -- borrow later used here
11+
|
12+
= note: consider using a `let` binding to create a longer lived value
1113

1214
error: aborting due to previous error
1315

src/test/ui/span/regions-close-over-borrowed-ref-in-obj.nll.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ LL | }
88
| - temporary value only lives until here
99
LL | }
1010
| - borrow later used here, when `blah` is dropped
11+
|
12+
= note: consider using a `let` binding to create a longer lived value
1113

1214
error: aborting due to previous error
1315

0 commit comments

Comments
 (0)