Skip to content

Commit ce8967a

Browse files
committed
Modified to output intended error.
1 parent a98aff7 commit ce8967a

File tree

1 file changed

+83
-21
lines changed

1 file changed

+83
-21
lines changed

src/librustc_mir/borrow_check.rs

+83-21
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use rustc_data_structures::indexed_set::{self, IdxSetBuf};
2525
use rustc_data_structures::indexed_vec::{Idx};
2626

2727
use syntax::ast::{self};
28-
use syntax_pos::{DUMMY_SP, Span};
28+
use syntax_pos::{DUMMY_SP, Span, MultiSpan};
2929

3030
use dataflow::{do_dataflow};
3131
use dataflow::{MoveDataParamEnv};
@@ -287,11 +287,14 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
287287
}
288288

289289
StatementKind::StorageDead(local) => {
290-
if self.storage_drop_or_dead_error_reported.insert(local) {
291-
self.access_lvalue(ContextKind::StorageDead.new(location),
292-
(&Lvalue::Local(local), span),
293-
(Shallow(None), Write(WriteKind::StorageDead)),
294-
flow_state);
290+
if !self.storage_drop_or_dead_error_reported.contains(&local) {
291+
let error_reported = self.access_lvalue(ContextKind::StorageDead.new(location),
292+
(&Lvalue::Local(local), span),
293+
(Shallow(None), Write(WriteKind::StorageDeadOrDrop)), flow_state);
294+
295+
if error_reported {
296+
self.storage_drop_or_dead_error_reported.insert(local);
297+
}
295298
}
296299
}
297300
}
@@ -435,24 +438,30 @@ enum ReadKind {
435438

436439
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
437440
enum WriteKind {
438-
StorageDead,
441+
StorageDeadOrDrop,
439442
MutableBorrow(BorrowKind),
440443
Mutate,
441444
Move,
442445
}
443446

444447
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
448+
/// Checks an access to the given lvalue to see if it is allowed. Examines the set of borrows
449+
/// that are in scope, as well as which paths have been initialized, to ensure that (a) the
450+
/// lvalue is initialized and (b) it is not borrowed in some way that would prevent this
451+
/// access.
452+
///
453+
/// Returns true if an error is reported, false otherwise.
445454
fn access_lvalue(&mut self,
446455
context: Context,
447456
lvalue_span: (&Lvalue<'tcx>, Span),
448457
kind: (ShallowOrDeep, ReadOrWrite),
449-
flow_state: &InProgress<'cx, 'gcx, 'tcx>) {
450-
458+
flow_state: &InProgress<'cx, 'gcx, 'tcx>) -> bool {
451459
let (sd, rw) = kind;
452460

453461
// Check permissions
454462
self.check_access_permissions(lvalue_span, rw);
455463

464+
let mut error_reported = false;
456465
self.each_borrow_involving_path(
457466
context, (sd, lvalue_span.0), flow_state, |this, _index, borrow, common_prefix| {
458467
match (rw, borrow.kind) {
@@ -462,13 +471,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
462471
(Read(kind), BorrowKind::Unique) |
463472
(Read(kind), BorrowKind::Mut) => {
464473
match kind {
465-
ReadKind::Copy =>
474+
ReadKind::Copy => {
475+
error_reported = true;
466476
this.report_use_while_mutably_borrowed(
467-
context, lvalue_span, borrow),
477+
context, lvalue_span, borrow)
478+
},
468479
ReadKind::Borrow(bk) => {
469480
let end_issued_loan_span =
470481
flow_state.borrows.base_results.operator().opt_region_end_span(
471482
&borrow.region);
483+
error_reported = true;
472484
this.report_conflicting_borrow(
473485
context, common_prefix, lvalue_span, bk,
474486
&borrow, end_issued_loan_span)
@@ -482,22 +494,35 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
482494
let end_issued_loan_span =
483495
flow_state.borrows.base_results.operator().opt_region_end_span(
484496
&borrow.region);
497+
error_reported = true;
485498
this.report_conflicting_borrow(
486499
context, common_prefix, lvalue_span, bk,
487500
&borrow, end_issued_loan_span)
488501
}
489-
WriteKind::StorageDead |
490-
WriteKind::Mutate =>
502+
WriteKind::StorageDeadOrDrop => {
503+
let end_span =
504+
flow_state.borrows.base_results.operator().opt_region_end_span(
505+
&borrow.region);
506+
error_reported = true;
507+
this.report_borrowed_value_does_not_live_long_enough(
508+
context, lvalue_span, end_span)
509+
},
510+
WriteKind::Mutate => {
511+
error_reported = true;
491512
this.report_illegal_mutation_of_borrowed(
492-
context, lvalue_span, borrow),
493-
WriteKind::Move =>
513+
context, lvalue_span, borrow)
514+
},
515+
WriteKind::Move => {
516+
error_reported = true;
494517
this.report_move_out_while_borrowed(
495-
context, lvalue_span, &borrow),
518+
context, lvalue_span, &borrow)
519+
},
496520
}
497521
Control::Break
498522
}
499523
}
500524
});
525+
error_reported
501526
}
502527

503528
fn mutate_lvalue(&mut self,
@@ -614,20 +639,34 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
614639

615640
// Check if error has already been reported to stop duplicate reporting.
616641
let has_storage_drop_or_dead_error_reported = match *lvalue {
617-
Lvalue::Local(local) => self.storage_drop_or_dead_error_reported.insert(local),
642+
Lvalue::Local(local) => self.storage_drop_or_dead_error_reported.contains(&local),
618643
_ => false,
619644
};
620645

646+
// If the error has been reported already, then we don't need the access_lvalue call and we
647+
// can set error_reported to false.
621648
if !has_storage_drop_or_dead_error_reported {
649+
let error_reported;
650+
622651
if moves_by_default {
652+
let kind = match consume_via_drop {
653+
ConsumeKind::Drop => WriteKind::StorageDeadOrDrop,
654+
_ => WriteKind::Move,
655+
};
623656
// move of lvalue: check if this is move of already borrowed path
624-
self.access_lvalue(context, lvalue_span, (Deep, Write(WriteKind::Move)),
625-
flow_state);
657+
error_reported = self.access_lvalue(context, lvalue_span,
658+
(Deep, Write(kind)), flow_state);
626659
} else {
627660
// copy of lvalue: check if this is "copy of frozen path"
628661
// (FIXME: see check_loans.rs)
629-
self.access_lvalue(context, lvalue_span, (Deep, Read(ReadKind::Copy)),
630-
flow_state);
662+
error_reported = self.access_lvalue(context, lvalue_span,
663+
(Deep, Read(ReadKind::Copy)), flow_state);
664+
}
665+
666+
if error_reported {
667+
if let Lvalue::Local(local) = *lvalue {
668+
self.storage_drop_or_dead_error_reported.insert(local);
669+
}
631670
}
632671
}
633672

@@ -1477,6 +1516,29 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
14771516
err.emit();
14781517
}
14791518

1519+
fn report_borrowed_value_does_not_live_long_enough(&mut self,
1520+
_: Context,
1521+
(lvalue, span): (&Lvalue, Span),
1522+
end_span: Option<Span>) {
1523+
let proper_span = match *lvalue {
1524+
Lvalue::Local(local) => self.mir.local_decls[local].source_info.span,
1525+
_ => span
1526+
};
1527+
1528+
let mut err = self.tcx.path_does_not_live_long_enough(proper_span,
1529+
"borrowed value", Origin::Mir);
1530+
err.span = MultiSpan::from_span(proper_span);
1531+
err.span_label(proper_span, "temporary value created here");
1532+
err.span_label(span, "temporary value dropped here while still borrowed");
1533+
err.note("consider using a `let` binding to increase its lifetime");
1534+
1535+
if let Some(end) = end_span {
1536+
err.span_label(end, "temporary value needs to live until here");
1537+
}
1538+
1539+
err.emit();
1540+
}
1541+
14801542
fn report_illegal_mutation_of_borrowed(&mut self,
14811543
_: Context,
14821544
(lvalue, span): (&Lvalue<'tcx>, Span),

0 commit comments

Comments
 (0)