Modified to output intended error.

This commit is contained in:
David Wood 2017-11-17 00:09:18 +00:00
parent a98aff7a5d
commit ce8967a7b3
No known key found for this signature in database
GPG Key ID: 01760B4F9F53F154

View File

@ -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),