Auto merge of #46598 - davidtwco:issue-46471, r=arielb1

MIR borrowck: error message confuses locals and temporaries

Fixes #46471 and fixes #46472 (see [this Gitter comment](https://gitter.im/rust-impl-period/WG-compiler-nll?at=5a2d5cb53ae2aa6b3facf0c2)).

r? @arielb1
This commit is contained in:
bors 2017-12-12 06:11:33 +00:00
commit 724500626b
21 changed files with 297 additions and 51 deletions

View File

@ -9,11 +9,14 @@
// except according to those terms.
use syntax_pos::Span;
use rustc::middle::region::ScopeTree;
use rustc::mir::{BorrowKind, Field, Local, Location, Operand};
use rustc::mir::{Place, ProjectionElem, Rvalue, StatementKind};
use rustc::ty;
use rustc::ty::{self, RegionKind};
use rustc_data_structures::indexed_vec::Idx;
use std::rc::Rc;
use super::{MirBorrowckCtxt, Context};
use super::{InitializationRequiringAction, PrefixSet};
use dataflow::{BorrowData, Borrows, FlowAtLocation, MovingOutStatements};
@ -324,6 +327,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
borrows: &Borrows<'cx, 'gcx, 'tcx>
) {
let end_span = borrows.opt_region_end_span(&borrow.region);
let scope_tree = borrows.scope_tree();
let root_place = self.prefixes(&borrow.place, PrefixSet::All).last().unwrap();
match root_place {
@ -347,21 +351,103 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
unreachable!("root_place is an unreachable???")
};
let borrow_span = self.mir.source_info(borrow.location).span;
let proper_span = match *root_place {
Place::Local(local) => self.mir.local_decls[local].source_info.span,
_ => drop_span,
};
let mut err = self.tcx
.path_does_not_live_long_enough(drop_span, "borrowed value", Origin::Mir);
match (borrow.region, &self.describe_place(&borrow.place)) {
(RegionKind::ReScope(_), Some(name)) => {
self.report_scoped_local_value_does_not_live_long_enough(
name, &scope_tree, &borrow, drop_span, borrow_span, proper_span, end_span);
},
(RegionKind::ReScope(_), None) => {
self.report_scoped_temporary_value_does_not_live_long_enough(
&scope_tree, &borrow, drop_span, borrow_span, proper_span, end_span);
},
(RegionKind::ReEarlyBound(_), Some(name)) |
(RegionKind::ReFree(_), Some(name)) |
(RegionKind::ReStatic, Some(name)) |
(RegionKind::ReEmpty, Some(name)) |
(RegionKind::ReVar(_), Some(name)) => {
self.report_unscoped_local_value_does_not_live_long_enough(
name, &scope_tree, &borrow, drop_span, borrow_span, proper_span, end_span);
},
(RegionKind::ReEarlyBound(_), None) |
(RegionKind::ReFree(_), None) |
(RegionKind::ReStatic, None) |
(RegionKind::ReEmpty, None) |
(RegionKind::ReVar(_), None) => {
self.report_unscoped_temporary_value_does_not_live_long_enough(
&scope_tree, &borrow, drop_span, borrow_span, proper_span, end_span);
},
(RegionKind::ReLateBound(_, _), _) |
(RegionKind::ReSkolemized(_, _), _) |
(RegionKind::ReErased, _) => {
span_bug!(drop_span, "region does not make sense in this context");
},
}
}
fn report_scoped_local_value_does_not_live_long_enough(
&mut self, name: &String, _scope_tree: &Rc<ScopeTree>, _borrow: &BorrowData<'tcx>,
drop_span: Span, borrow_span: Span, _proper_span: Span, end_span: Option<Span>
) {
let mut err = self.tcx.path_does_not_live_long_enough(drop_span,
&format!("`{}`", name),
Origin::Mir);
err.span_label(borrow_span, "borrow occurs here");
err.span_label(drop_span, format!("`{}` dropped here while still borrowed", name));
if let Some(end) = end_span {
err.span_label(end, "borrowed value needs to live until here");
}
err.emit();
}
fn report_scoped_temporary_value_does_not_live_long_enough(
&mut self, _scope_tree: &Rc<ScopeTree>, _borrow: &BorrowData<'tcx>,
drop_span: Span, borrow_span: Span, proper_span: Span, end_span: Option<Span>
) {
let mut err = self.tcx.path_does_not_live_long_enough(borrow_span,
"borrowed value",
Origin::Mir);
err.span_label(proper_span, "temporary value created here");
err.span_label(drop_span, "temporary value dropped here while still borrowed");
err.note("consider using a `let` binding to increase its lifetime");
if let Some(end) = end_span {
err.span_label(end, "temporary value needs to live until here");
}
err.emit();
}
fn report_unscoped_local_value_does_not_live_long_enough(
&mut self, name: &String, scope_tree: &Rc<ScopeTree>, borrow: &BorrowData<'tcx>,
drop_span: Span, borrow_span: Span, _proper_span: Span, _end_span: Option<Span>
) {
let mut err = self.tcx.path_does_not_live_long_enough(borrow_span,
&format!("`{}`", name),
Origin::Mir);
err.span_label(borrow_span, "does not live long enough");
err.span_label(drop_span, "borrowed value only lives until here");
self.tcx.note_and_explain_region(scope_tree, &mut err,
"borrowed value must be valid for ",
borrow.region, "...");
err.emit();
}
fn report_unscoped_temporary_value_does_not_live_long_enough(
&mut self, scope_tree: &Rc<ScopeTree>, borrow: &BorrowData<'tcx>,
drop_span: Span, _borrow_span: Span, proper_span: Span, _end_span: Option<Span>
) {
let mut err = self.tcx.path_does_not_live_long_enough(proper_span,
"borrowed value",
Origin::Mir);
err.span_label(proper_span, "does not live long enough");
err.span_label(drop_span, "temporary value only lives until here");
self.tcx.note_and_explain_region(scope_tree, &mut err,
"borrowed value must be valid for ",
borrow.region, "...");
err.emit();
}

View File

@ -1800,7 +1800,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
}
}
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
// FIXME (#16118): function intended to allow the borrow checker
// to be less precise in its handling of Box while still allowing

View File

@ -160,6 +160,8 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
pub fn borrows(&self) -> &IndexVec<BorrowIndex, BorrowData<'tcx>> { &self.borrows }
pub fn scope_tree(&self) -> &Rc<region::ScopeTree> { &self.scope_tree }
pub fn location(&self, idx: BorrowIndex) -> &Location {
&self.borrows[idx].location
}

View File

@ -12,8 +12,9 @@
//[mir]compile-flags: -Z borrowck=mir
fn cplusplus_mode(x: isize) -> &'static isize {
&x //[ast]~ ERROR `x` does not live long enough
&x
//[ast]~^ ERROR `x` does not live long enough [E0597]
//[mir]~^^ ERROR `x` does not live long enough [E0597]
}
//[mir]~^ ERROR borrowed value does not live long enough
fn main() {}

View File

@ -13,10 +13,11 @@
fn cplusplus_mode_exceptionally_unsafe(x: &mut Option<&'static mut isize>) {
let mut z = (0, 0);
*x = Some(&mut z.1); //[ast]~ ERROR [E0597]
*x = Some(&mut z.1);
//[ast]~^ ERROR `z.1` does not live long enough [E0597]
//[mir]~^^ ERROR `z.1` does not live long enough [E0597]
panic!("catch me for a dangling pointer!")
}
//[mir]~^ ERROR [E0597]
fn main() {
cplusplus_mode_exceptionally_unsafe(&mut None);

View File

@ -18,12 +18,16 @@ static FOO: u8 = 3;
fn main() {
let a = &FOO;
//[ast]~^ ERROR borrowed value does not live long enough
//[mir]~^ ERROR `FOO` does not live long enough [E0597]
//[mir]~| does not live long enough
//[mir]~| NOTE borrowed value must be valid for the static lifetime
//[ast]~^^^^ ERROR borrowed value does not live long enough
//[ast]~| does not live long enough
//[ast]~| NOTE borrowed value must be valid for the static lifetime
std::thread::spawn(move || {
println!("{}", a);
});
} //[ast]~ temporary value only lives until here
//[mir]~^ ERROR borrowed value does not live long enough
}
//[mir]~^ borrowed value only lives until here
//[ast]~^^ temporary value only lives until here

View File

@ -82,8 +82,8 @@ fn main() {
//[ast]~^ ERROR `x` does not live long enough
//[ast]~| ERROR `y` does not live long enough
});
//[mir]~^ ERROR borrowed value does not live long enough
//[mir]~| ERROR borrowed value does not live long enough
//[mir]~^ ERROR `x` does not live long enough
//[mir]~| ERROR `y` does not live long enough
w.handle(); // This works
// w.handle_ref(); // This doesn't

View File

@ -0,0 +1,21 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z emit-end-regions -Z borrowck=compare
fn main() {
let y = {
let mut z = 0;
&mut z
};
//~^ ERROR `z` does not live long enough (Ast) [E0597]
//~| ERROR `z` does not live long enough (Mir) [E0597]
println!("{}", y);
}

View File

@ -0,0 +1,24 @@
error[E0597]: `z` does not live long enough (Ast)
--> $DIR/issue-46471-1.rs:17:5
|
16 | &mut z
| - borrow occurs here
17 | };
| ^ `z` dropped here while still borrowed
...
21 | }
| - borrowed value needs to live until here
error[E0597]: `z` does not live long enough (Mir)
--> $DIR/issue-46471-1.rs:17:6
|
16 | &mut z
| ------ borrow occurs here
17 | };
| ^ `z` dropped here while still borrowed
...
21 | }
| - borrowed value needs to live until here
error: aborting due to 2 previous errors

View File

@ -0,0 +1,20 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z emit-end-regions -Z borrowck=compare
fn foo() -> &'static u32 {
let x = 0;
&x
//~^ ERROR `x` does not live long enough (Ast) [E0597]
//~| ERROR `x` does not live long enough (Mir) [E0597]
}
fn main() { }

View File

@ -0,0 +1,24 @@
error[E0597]: `x` does not live long enough (Ast)
--> $DIR/issue-46471.rs:15:6
|
15 | &x
| ^ does not live long enough
...
18 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
error[E0597]: `x` does not live long enough (Mir)
--> $DIR/issue-46471.rs:15:5
|
15 | &x
| ^^ does not live long enough
...
18 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
error: aborting due to 2 previous errors

View File

@ -0,0 +1,19 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z emit-end-regions -Z borrowck=compare
fn bar<'a>() -> &'a mut u32 {
&mut 4
//~^ ERROR borrowed value does not live long enough (Ast) [E0597]
//~| ERROR borrowed value does not live long enough (Mir) [E0597]
}
fn main() { }

View File

@ -0,0 +1,40 @@
error[E0597]: borrowed value does not live long enough (Ast)
--> $DIR/issue-46472.rs:14:10
|
14 | &mut 4
| ^ does not live long enough
...
17 | }
| - temporary value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 13:1...
--> $DIR/issue-46472.rs:13:1
|
13 | / fn bar<'a>() -> &'a mut u32 {
14 | | &mut 4
15 | | //~^ ERROR borrowed value does not live long enough (Ast) [E0597]
16 | | //~| ERROR borrowed value does not live long enough (Mir) [E0597]
17 | | }
| |_^
error[E0597]: borrowed value does not live long enough (Mir)
--> $DIR/issue-46472.rs:14:10
|
14 | &mut 4
| ^ does not live long enough
...
17 | }
| - temporary value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 13:1...
--> $DIR/issue-46472.rs:13:1
|
13 | / fn bar<'a>() -> &'a mut u32 {
14 | | &mut 4
15 | | //~^ ERROR borrowed value does not live long enough (Ast) [E0597]
16 | | //~| ERROR borrowed value does not live long enough (Mir) [E0597]
17 | | }
| |_^
error: aborting due to 2 previous errors

View File

@ -30,11 +30,11 @@ fn test() {
let closure = SomeStruct {
p: &mut p,
y: &y,
//~^ ERROR `y` does not live long enough [E0597]
};
closure.invoke();
}
//~^ ERROR borrowed value does not live long enough [E0597]
deref(p);
}

View File

@ -1,13 +1,13 @@
error[E0597]: borrowed value does not live long enough
--> $DIR/capture-ref-in-struct.rs:36:6
error[E0597]: `y` does not live long enough
--> $DIR/capture-ref-in-struct.rs:32:16
|
28 | let y = 22;
| - temporary value created here
32 | y: &y,
| ^^ does not live long enough
...
36 | }
| ^ temporary value dropped here while still borrowed
37 | }
| - borrowed value only lives until here
|
= note: consider using a `let` binding to increase its lifetime
= note: borrowed value must be valid for lifetime '_#4r...
error: aborting due to previous error

View File

@ -35,8 +35,8 @@ fn test() {
let y = 22;
let mut closure = expect_sig(|p, y| *p = y);
closure(&mut p, &y);
//~^ ERROR `y` does not live long enough [E0597]
}
//~^ ERROR borrowed value does not live long enough [E0597]
deref(p);
}

View File

@ -24,16 +24,16 @@ note: No external requirements
|
= note: defining type: DefId(0/0:3 ~ escape_argument[317d]::test[0]) with substs []
error[E0597]: borrowed value does not live long enough
--> $DIR/escape-argument.rs:38:6
error[E0597]: `y` does not live long enough
--> $DIR/escape-argument.rs:37:25
|
35 | let y = 22;
| - temporary value created here
...
38 | }
| ^ temporary value dropped here while still borrowed
37 | closure(&mut p, &y);
| ^^ does not live long enough
38 | //~^ ERROR `y` does not live long enough [E0597]
39 | }
| - borrowed value only lives until here
|
= note: consider using a `let` binding to increase its lifetime
= note: borrowed value must be valid for lifetime '_#5r...
error: aborting due to previous error

View File

@ -27,13 +27,13 @@ fn test() {
{
let y = 22;
let mut closure = || {
let mut closure = || { //~ ERROR `y` does not live long enough [E0597]
let mut closure1 = || p = &y;
closure1();
};
closure();
} //~ ERROR borrowed value does not live long enough
}
deref(p);
}

View File

@ -16,7 +16,7 @@ note: External requirements
note: External requirements
--> $DIR/escape-upvar-nested.rs:30:27
|
30 | let mut closure = || {
30 | let mut closure = || { //~ ERROR `y` does not live long enough [E0597]
| ___________________________^
31 | | let mut closure1 = || p = &y;
32 | | closure1();
@ -46,16 +46,20 @@ note: No external requirements
|
= note: defining type: DefId(0/0:3 ~ escape_upvar_nested[317d]::test[0]) with substs []
error[E0597]: borrowed value does not live long enough
--> $DIR/escape-upvar-nested.rs:36:6
error[E0597]: `y` does not live long enough
--> $DIR/escape-upvar-nested.rs:30:27
|
28 | let y = 22;
| - temporary value created here
30 | let mut closure = || { //~ ERROR `y` does not live long enough [E0597]
| ___________________________^
31 | | let mut closure1 = || p = &y;
32 | | closure1();
33 | | };
| |_________^ does not live long enough
...
36 | } //~ ERROR borrowed value does not live long enough
| ^ temporary value dropped here while still borrowed
36 | }
| - borrowed value only lives until here
|
= note: consider using a `let` binding to increase its lifetime
= note: borrowed value must be valid for lifetime '_#3r...
error: aborting due to previous error

View File

@ -31,8 +31,9 @@ fn test() {
{
let y = 22;
let mut closure = || p = &y;
//~^ ERROR `y` does not live long enough [E0597]
closure();
} //~ ERROR borrowed value does not live long enough
}
deref(p);
}

View File

@ -21,22 +21,22 @@ note: No external requirements
29 | | let mut p = &x;
30 | |
... |
37 | | deref(p);
38 | | }
38 | | deref(p);
39 | | }
| |_^
|
= note: defining type: DefId(0/0:3 ~ escape_upvar_ref[317d]::test[0]) with substs []
error[E0597]: borrowed value does not live long enough
--> $DIR/escape-upvar-ref.rs:35:6
error[E0597]: `y` does not live long enough
--> $DIR/escape-upvar-ref.rs:33:27
|
32 | let y = 22;
| - temporary value created here
33 | let mut closure = || p = &y;
| ^^^^^^^^^ does not live long enough
...
35 | } //~ ERROR borrowed value does not live long enough
| ^ temporary value dropped here while still borrowed
36 | }
| - borrowed value only lives until here
|
= note: consider using a `let` binding to increase its lifetime
= note: borrowed value must be valid for lifetime '_#3r...
error: aborting due to previous error