@@ -25,7 +25,7 @@ use rustc_data_structures::indexed_set::{self, IdxSetBuf};
25
25
use rustc_data_structures:: indexed_vec:: { Idx } ;
26
26
27
27
use syntax:: ast:: { self } ;
28
- use syntax_pos:: { DUMMY_SP , Span } ;
28
+ use syntax_pos:: { DUMMY_SP , Span , MultiSpan } ;
29
29
30
30
use dataflow:: { do_dataflow} ;
31
31
use dataflow:: { MoveDataParamEnv } ;
@@ -287,11 +287,14 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
287
287
}
288
288
289
289
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
+ }
295
298
}
296
299
}
297
300
}
@@ -435,24 +438,30 @@ enum ReadKind {
435
438
436
439
#[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
437
440
enum WriteKind {
438
- StorageDead ,
441
+ StorageDeadOrDrop ,
439
442
MutableBorrow ( BorrowKind ) ,
440
443
Mutate ,
441
444
Move ,
442
445
}
443
446
444
447
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.
445
454
fn access_lvalue ( & mut self ,
446
455
context : Context ,
447
456
lvalue_span : ( & Lvalue < ' tcx > , Span ) ,
448
457
kind : ( ShallowOrDeep , ReadOrWrite ) ,
449
- flow_state : & InProgress < ' cx , ' gcx , ' tcx > ) {
450
-
458
+ flow_state : & InProgress < ' cx , ' gcx , ' tcx > ) -> bool {
451
459
let ( sd, rw) = kind;
452
460
453
461
// Check permissions
454
462
self . check_access_permissions ( lvalue_span, rw) ;
455
463
464
+ let mut error_reported = false ;
456
465
self . each_borrow_involving_path (
457
466
context, ( sd, lvalue_span. 0 ) , flow_state, |this, _index, borrow, common_prefix| {
458
467
match ( rw, borrow. kind ) {
@@ -462,13 +471,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
462
471
( Read ( kind) , BorrowKind :: Unique ) |
463
472
( Read ( kind) , BorrowKind :: Mut ) => {
464
473
match kind {
465
- ReadKind :: Copy =>
474
+ ReadKind :: Copy => {
475
+ error_reported = true ;
466
476
this. report_use_while_mutably_borrowed (
467
- context, lvalue_span, borrow) ,
477
+ context, lvalue_span, borrow)
478
+ } ,
468
479
ReadKind :: Borrow ( bk) => {
469
480
let end_issued_loan_span =
470
481
flow_state. borrows . base_results . operator ( ) . opt_region_end_span (
471
482
& borrow. region ) ;
483
+ error_reported = true ;
472
484
this. report_conflicting_borrow (
473
485
context, common_prefix, lvalue_span, bk,
474
486
& borrow, end_issued_loan_span)
@@ -482,22 +494,35 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
482
494
let end_issued_loan_span =
483
495
flow_state. borrows . base_results . operator ( ) . opt_region_end_span (
484
496
& borrow. region ) ;
497
+ error_reported = true ;
485
498
this. report_conflicting_borrow (
486
499
context, common_prefix, lvalue_span, bk,
487
500
& borrow, end_issued_loan_span)
488
501
}
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 ;
491
512
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 ;
494
517
this. report_move_out_while_borrowed (
495
- context, lvalue_span, & borrow) ,
518
+ context, lvalue_span, & borrow)
519
+ } ,
496
520
}
497
521
Control :: Break
498
522
}
499
523
}
500
524
} ) ;
525
+ error_reported
501
526
}
502
527
503
528
fn mutate_lvalue ( & mut self ,
@@ -614,20 +639,34 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
614
639
615
640
// Check if error has already been reported to stop duplicate reporting.
616
641
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) ,
618
643
_ => false ,
619
644
} ;
620
645
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.
621
648
if !has_storage_drop_or_dead_error_reported {
649
+ let error_reported;
650
+
622
651
if moves_by_default {
652
+ let kind = match consume_via_drop {
653
+ ConsumeKind :: Drop => WriteKind :: StorageDeadOrDrop ,
654
+ _ => WriteKind :: Move ,
655
+ } ;
623
656
// 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) ;
626
659
} else {
627
660
// copy of lvalue: check if this is "copy of frozen path"
628
661
// (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
+ }
631
670
}
632
671
}
633
672
@@ -1477,6 +1516,29 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1477
1516
err. emit ( ) ;
1478
1517
}
1479
1518
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
+
1480
1542
fn report_illegal_mutation_of_borrowed ( & mut self ,
1481
1543
_: Context ,
1482
1544
( lvalue, span) : ( & Lvalue < ' tcx > , Span ) ,
0 commit comments