@@ -25,7 +25,7 @@ use rustc_data_structures::indexed_set::{self, IdxSetBuf};
2525use rustc_data_structures:: indexed_vec:: { Idx } ;
2626
2727use syntax:: ast:: { self } ;
28- use syntax_pos:: { DUMMY_SP , Span } ;
28+ use syntax_pos:: { DUMMY_SP , Span , MultiSpan } ;
2929
3030use dataflow:: { do_dataflow} ;
3131use 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 ) ]
437440enum WriteKind {
438- StorageDead ,
441+ StorageDeadOrDrop ,
439442 MutableBorrow ( BorrowKind ) ,
440443 Mutate ,
441444 Move ,
442445}
443446
444447impl < ' 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