improve conflict error reporting
This commit is contained in:
parent
f8c35d9e41
commit
cbcae7f694
@ -548,14 +548,13 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
|||||||
|
|
||||||
if self.place_is_invalidated_at_exit(&borrow.place) {
|
if self.place_is_invalidated_at_exit(&borrow.place) {
|
||||||
debug!("borrow conflicts at exit {:?}", borrow);
|
debug!("borrow conflicts at exit {:?}", borrow);
|
||||||
let borrow_span = self.mir.source_info(borrow.location).span;
|
|
||||||
// FIXME: should be talking about the region lifetime instead
|
// FIXME: should be talking about the region lifetime instead
|
||||||
// of just a span here.
|
// of just a span here.
|
||||||
let end_span = domain.opt_region_end_span(&borrow.region);
|
let end_span = domain.opt_region_end_span(&borrow.region);
|
||||||
|
|
||||||
self.report_borrowed_value_does_not_live_long_enough(
|
self.report_borrowed_value_does_not_live_long_enough(
|
||||||
ContextKind::StorageDead.new(loc),
|
ContextKind::StorageDead.new(loc),
|
||||||
(&borrow.place, borrow_span),
|
(&borrow.place, end_span.unwrap_or(span)),
|
||||||
end_span,
|
end_span,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -958,7 +957,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
/// Returns whether a borrow of this place is invalidated when the function
|
/// Returns whether a borrow of this place is invalidated when the function
|
||||||
/// exits
|
/// exits
|
||||||
fn place_is_invalidated_at_exit(&self, place: &Place<'tcx>) -> bool {
|
fn place_is_invalidated_at_exit(&mut self, place: &Place<'tcx>) -> bool {
|
||||||
debug!("place_is_invalidated_at_exit({:?})", place);
|
debug!("place_is_invalidated_at_exit({:?})", place);
|
||||||
let root_place = self.prefixes(place, PrefixSet::All).last().unwrap();
|
let root_place = self.prefixes(place, PrefixSet::All).last().unwrap();
|
||||||
|
|
||||||
@ -967,7 +966,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
// we'll have a memory leak) and assume that all statics have a destructor.
|
// we'll have a memory leak) and assume that all statics have a destructor.
|
||||||
//
|
//
|
||||||
// FIXME: allow thread-locals to borrow other thread locals?x
|
// FIXME: allow thread-locals to borrow other thread locals?x
|
||||||
let (might_be_alive, will_be_dropped) = match root_place {
|
let (might_be_alive, will_be_dropped, local) = match root_place {
|
||||||
Place::Static(statik) => {
|
Place::Static(statik) => {
|
||||||
// Thread-locals might be dropped after the function exits, but
|
// Thread-locals might be dropped after the function exits, but
|
||||||
// "true" statics will never be.
|
// "true" statics will never be.
|
||||||
@ -976,12 +975,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
.iter()
|
.iter()
|
||||||
.any(|attr| attr.check_name("thread_local"));
|
.any(|attr| attr.check_name("thread_local"));
|
||||||
|
|
||||||
(true, is_thread_local)
|
(true, is_thread_local, None)
|
||||||
}
|
}
|
||||||
Place::Local(_) => {
|
Place::Local(local) => {
|
||||||
// Locals are always dropped at function exit, and if they
|
// Locals are always dropped at function exit, and if they
|
||||||
// have a destructor it would've been called already.
|
// have a destructor it would've been called already.
|
||||||
(false, self.locals_are_invalidated_at_exit)
|
(false, self.locals_are_invalidated_at_exit, Some(*local))
|
||||||
}
|
}
|
||||||
Place::Projection(..) => {
|
Place::Projection(..) => {
|
||||||
bug!("root of {:?} is a projection ({:?})?", place, root_place)
|
bug!("root of {:?} is a projection ({:?})?", place, root_place)
|
||||||
@ -1004,8 +1003,19 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
PrefixSet::Shallow
|
PrefixSet::Shallow
|
||||||
};
|
};
|
||||||
|
|
||||||
self.prefixes(place, prefix_set)
|
let result =
|
||||||
.any(|prefix| prefix == root_place)
|
self.prefixes(place, prefix_set).any(|prefix| prefix == root_place);
|
||||||
|
|
||||||
|
if result {
|
||||||
|
if let Some(local) = local {
|
||||||
|
if let Some(_) = self.storage_dead_or_drop_error_reported.replace(local) {
|
||||||
|
debug!("place_is_invalidated_at_exit({:?}) - suppressed", place);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
fn cplusplus_mode(x: isize) -> &'static isize {
|
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
|
||||||
//[mir]~^ ERROR borrowed value does not live long enough
|
|
||||||
}
|
}
|
||||||
|
//[mir]~^ ERROR borrowed value does not live long enough
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
fn cplusplus_mode_exceptionally_unsafe(x: &mut Option<&'static mut isize>) {
|
fn cplusplus_mode_exceptionally_unsafe(x: &mut Option<&'static mut isize>) {
|
||||||
let mut z = (0, 0);
|
let mut z = (0, 0);
|
||||||
*x = Some(&mut z.1); //[ast]~ ERROR [E0597]
|
*x = Some(&mut z.1); //[ast]~ ERROR [E0597]
|
||||||
//[mir]~^ ERROR [E0597]
|
|
||||||
panic!("catch me for a dangling pointer!")
|
panic!("catch me for a dangling pointer!")
|
||||||
}
|
}
|
||||||
|
//[mir]~^ ERROR [E0597]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
cplusplus_mode_exceptionally_unsafe(&mut None);
|
cplusplus_mode_exceptionally_unsafe(&mut None);
|
||||||
|
Loading…
Reference in New Issue
Block a user