Modified to output intended error.
This commit is contained in:
parent
a98aff7a5d
commit
ce8967a7b3
@ -25,7 +25,7 @@ use rustc_data_structures::indexed_set::{self, IdxSetBuf};
|
||||
use rustc_data_structures::indexed_vec::{Idx};
|
||||
|
||||
use syntax::ast::{self};
|
||||
use syntax_pos::{DUMMY_SP, Span};
|
||||
use syntax_pos::{DUMMY_SP, Span, MultiSpan};
|
||||
|
||||
use dataflow::{do_dataflow};
|
||||
use dataflow::{MoveDataParamEnv};
|
||||
@ -287,11 +287,14 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
||||
}
|
||||
|
||||
StatementKind::StorageDead(local) => {
|
||||
if self.storage_drop_or_dead_error_reported.insert(local) {
|
||||
self.access_lvalue(ContextKind::StorageDead.new(location),
|
||||
(&Lvalue::Local(local), span),
|
||||
(Shallow(None), Write(WriteKind::StorageDead)),
|
||||
flow_state);
|
||||
if !self.storage_drop_or_dead_error_reported.contains(&local) {
|
||||
let error_reported = self.access_lvalue(ContextKind::StorageDead.new(location),
|
||||
(&Lvalue::Local(local), span),
|
||||
(Shallow(None), Write(WriteKind::StorageDeadOrDrop)), flow_state);
|
||||
|
||||
if error_reported {
|
||||
self.storage_drop_or_dead_error_reported.insert(local);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -435,24 +438,30 @@ enum ReadKind {
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
enum WriteKind {
|
||||
StorageDead,
|
||||
StorageDeadOrDrop,
|
||||
MutableBorrow(BorrowKind),
|
||||
Mutate,
|
||||
Move,
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
/// Checks an access to the given lvalue to see if it is allowed. Examines the set of borrows
|
||||
/// that are in scope, as well as which paths have been initialized, to ensure that (a) the
|
||||
/// lvalue is initialized and (b) it is not borrowed in some way that would prevent this
|
||||
/// access.
|
||||
///
|
||||
/// Returns true if an error is reported, false otherwise.
|
||||
fn access_lvalue(&mut self,
|
||||
context: Context,
|
||||
lvalue_span: (&Lvalue<'tcx>, Span),
|
||||
kind: (ShallowOrDeep, ReadOrWrite),
|
||||
flow_state: &InProgress<'cx, 'gcx, 'tcx>) {
|
||||
|
||||
flow_state: &InProgress<'cx, 'gcx, 'tcx>) -> bool {
|
||||
let (sd, rw) = kind;
|
||||
|
||||
// Check permissions
|
||||
self.check_access_permissions(lvalue_span, rw);
|
||||
|
||||
let mut error_reported = false;
|
||||
self.each_borrow_involving_path(
|
||||
context, (sd, lvalue_span.0), flow_state, |this, _index, borrow, common_prefix| {
|
||||
match (rw, borrow.kind) {
|
||||
@ -462,13 +471,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
(Read(kind), BorrowKind::Unique) |
|
||||
(Read(kind), BorrowKind::Mut) => {
|
||||
match kind {
|
||||
ReadKind::Copy =>
|
||||
ReadKind::Copy => {
|
||||
error_reported = true;
|
||||
this.report_use_while_mutably_borrowed(
|
||||
context, lvalue_span, borrow),
|
||||
context, lvalue_span, borrow)
|
||||
},
|
||||
ReadKind::Borrow(bk) => {
|
||||
let end_issued_loan_span =
|
||||
flow_state.borrows.base_results.operator().opt_region_end_span(
|
||||
&borrow.region);
|
||||
error_reported = true;
|
||||
this.report_conflicting_borrow(
|
||||
context, common_prefix, lvalue_span, bk,
|
||||
&borrow, end_issued_loan_span)
|
||||
@ -482,22 +494,35 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
let end_issued_loan_span =
|
||||
flow_state.borrows.base_results.operator().opt_region_end_span(
|
||||
&borrow.region);
|
||||
error_reported = true;
|
||||
this.report_conflicting_borrow(
|
||||
context, common_prefix, lvalue_span, bk,
|
||||
&borrow, end_issued_loan_span)
|
||||
}
|
||||
WriteKind::StorageDead |
|
||||
WriteKind::Mutate =>
|
||||
WriteKind::StorageDeadOrDrop => {
|
||||
let end_span =
|
||||
flow_state.borrows.base_results.operator().opt_region_end_span(
|
||||
&borrow.region);
|
||||
error_reported = true;
|
||||
this.report_borrowed_value_does_not_live_long_enough(
|
||||
context, lvalue_span, end_span)
|
||||
},
|
||||
WriteKind::Mutate => {
|
||||
error_reported = true;
|
||||
this.report_illegal_mutation_of_borrowed(
|
||||
context, lvalue_span, borrow),
|
||||
WriteKind::Move =>
|
||||
context, lvalue_span, borrow)
|
||||
},
|
||||
WriteKind::Move => {
|
||||
error_reported = true;
|
||||
this.report_move_out_while_borrowed(
|
||||
context, lvalue_span, &borrow),
|
||||
context, lvalue_span, &borrow)
|
||||
},
|
||||
}
|
||||
Control::Break
|
||||
}
|
||||
}
|
||||
});
|
||||
error_reported
|
||||
}
|
||||
|
||||
fn mutate_lvalue(&mut self,
|
||||
@ -614,20 +639,34 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
|
||||
// Check if error has already been reported to stop duplicate reporting.
|
||||
let has_storage_drop_or_dead_error_reported = match *lvalue {
|
||||
Lvalue::Local(local) => self.storage_drop_or_dead_error_reported.insert(local),
|
||||
Lvalue::Local(local) => self.storage_drop_or_dead_error_reported.contains(&local),
|
||||
_ => false,
|
||||
};
|
||||
|
||||
// If the error has been reported already, then we don't need the access_lvalue call and we
|
||||
// can set error_reported to false.
|
||||
if !has_storage_drop_or_dead_error_reported {
|
||||
let error_reported;
|
||||
|
||||
if moves_by_default {
|
||||
let kind = match consume_via_drop {
|
||||
ConsumeKind::Drop => WriteKind::StorageDeadOrDrop,
|
||||
_ => WriteKind::Move,
|
||||
};
|
||||
// move of lvalue: check if this is move of already borrowed path
|
||||
self.access_lvalue(context, lvalue_span, (Deep, Write(WriteKind::Move)),
|
||||
flow_state);
|
||||
error_reported = self.access_lvalue(context, lvalue_span,
|
||||
(Deep, Write(kind)), flow_state);
|
||||
} else {
|
||||
// copy of lvalue: check if this is "copy of frozen path"
|
||||
// (FIXME: see check_loans.rs)
|
||||
self.access_lvalue(context, lvalue_span, (Deep, Read(ReadKind::Copy)),
|
||||
flow_state);
|
||||
error_reported = self.access_lvalue(context, lvalue_span,
|
||||
(Deep, Read(ReadKind::Copy)), flow_state);
|
||||
}
|
||||
|
||||
if error_reported {
|
||||
if let Lvalue::Local(local) = *lvalue {
|
||||
self.storage_drop_or_dead_error_reported.insert(local);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1477,6 +1516,29 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
err.emit();
|
||||
}
|
||||
|
||||
fn report_borrowed_value_does_not_live_long_enough(&mut self,
|
||||
_: Context,
|
||||
(lvalue, span): (&Lvalue, Span),
|
||||
end_span: Option<Span>) {
|
||||
let proper_span = match *lvalue {
|
||||
Lvalue::Local(local) => self.mir.local_decls[local].source_info.span,
|
||||
_ => span
|
||||
};
|
||||
|
||||
let mut err = self.tcx.path_does_not_live_long_enough(proper_span,
|
||||
"borrowed value", Origin::Mir);
|
||||
err.span = MultiSpan::from_span(proper_span);
|
||||
err.span_label(proper_span, "temporary value created here");
|
||||
err.span_label(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_illegal_mutation_of_borrowed(&mut self,
|
||||
_: Context,
|
||||
(lvalue, span): (&Lvalue<'tcx>, Span),
|
||||
|
Loading…
x
Reference in New Issue
Block a user