Skip to content

MIR borrowck: error message confuses locals and temporaries #46598

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Dec 12, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 90 additions & 4 deletions src/librustc_mir/borrow_check/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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 {
Expand All @@ -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();
}

Expand Down
1 change: 0 additions & 1 deletion src/librustc_mir/borrow_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_mir/dataflow/impls/borrows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 7 additions & 3 deletions src/test/compile-fail/issue-17954.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 2 additions & 2 deletions src/test/compile-fail/region-borrow-params-issue-29793-big.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 21 additions & 0 deletions src/test/ui/issue-46471-1.rs
Original file line number Diff line number Diff line change
@@ -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);
}
24 changes: 24 additions & 0 deletions src/test/ui/issue-46471-1.stderr
Original file line number Diff line number Diff line change
@@ -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

20 changes: 20 additions & 0 deletions src/test/ui/issue-46471.rs
Original file line number Diff line number Diff line change
@@ -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() { }
24 changes: 24 additions & 0 deletions src/test/ui/issue-46471.stderr
Original file line number Diff line number Diff line change
@@ -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

19 changes: 19 additions & 0 deletions src/test/ui/issue-46472.rs
Original file line number Diff line number Diff line change
@@ -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() { }
40 changes: 40 additions & 0 deletions src/test/ui/issue-46472.stderr
Original file line number Diff line number Diff line change
@@ -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

2 changes: 1 addition & 1 deletion src/test/ui/nll/capture-ref-in-struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
14 changes: 7 additions & 7 deletions src/test/ui/nll/capture-ref-in-struct.stderr
Original file line number Diff line number Diff line change
@@ -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

Loading