@@ -150,9 +150,9 @@ pub fn check_loans(bccx: &BorrowckCtxt,
150
150
}
151
151
152
152
#[ deriving( PartialEq ) ]
153
- enum MoveError {
154
- MoveOk ,
155
- MoveWhileBorrowed ( /*loan*/ Rc < LoanPath > , /*loan*/ Span )
153
+ enum UseError {
154
+ UseOk ,
155
+ UseWhileBorrowed ( /*loan*/ Rc < LoanPath > , /*loan*/ Span )
156
156
}
157
157
158
158
impl < ' a > CheckLoanCtxt < ' a > {
@@ -438,8 +438,7 @@ impl<'a> CheckLoanCtxt<'a> {
438
438
Some ( lp) => {
439
439
let moved_value_use_kind = match mode {
440
440
euv:: Copy => {
441
- // FIXME(#12624) -- If we are copying the value,
442
- // we don't care if it's borrowed.
441
+ self . check_for_copy_of_frozen_path ( id, span, & * lp) ;
443
442
MovedInUse
444
443
}
445
444
euv:: Move ( _) => {
@@ -454,7 +453,7 @@ impl<'a> CheckLoanCtxt<'a> {
454
453
}
455
454
Some ( move_kind) => {
456
455
self . check_for_move_of_borrowed_path ( id, span,
457
- & lp, move_kind) ;
456
+ & * lp, move_kind) ;
458
457
if move_kind == move_data:: Captured {
459
458
MovedInCapture
460
459
} else {
@@ -471,23 +470,47 @@ impl<'a> CheckLoanCtxt<'a> {
471
470
}
472
471
}
473
472
473
+ fn check_for_copy_of_frozen_path ( & self ,
474
+ id : ast:: NodeId ,
475
+ span : Span ,
476
+ copy_path : & LoanPath ) {
477
+ match self . analyze_restrictions_on_use ( id, copy_path, ty:: ImmBorrow ) {
478
+ UseOk => { }
479
+ UseWhileBorrowed ( loan_path, loan_span) => {
480
+ self . bccx . span_err (
481
+ span,
482
+ format ! ( "cannot use `{}` because it was mutably borrowed" ,
483
+ self . bccx. loan_path_to_str( copy_path) . as_slice( ) )
484
+ . as_slice ( ) ) ;
485
+ self . bccx . span_note (
486
+ loan_span,
487
+ format ! ( "borrow of `{}` occurs here" ,
488
+ self . bccx. loan_path_to_str( & * loan_path) . as_slice( ) )
489
+ . as_slice ( ) ) ;
490
+ }
491
+ }
492
+ }
493
+
474
494
fn check_for_move_of_borrowed_path ( & self ,
475
495
id : ast:: NodeId ,
476
496
span : Span ,
477
- move_path : & Rc < LoanPath > ,
497
+ move_path : & LoanPath ,
478
498
move_kind : move_data:: MoveKind ) {
479
- match self . analyze_move_out_from ( id, & * * move_path) {
480
- MoveOk => { }
481
- MoveWhileBorrowed ( loan_path, loan_span) => {
499
+ // We want to detect if there are any loans at all, so we search for
500
+ // any loans incompatible with MutBorrrow, since all other kinds of
501
+ // loans are incompatible with that.
502
+ match self . analyze_restrictions_on_use ( id, move_path, ty:: MutBorrow ) {
503
+ UseOk => { }
504
+ UseWhileBorrowed ( loan_path, loan_span) => {
482
505
let err_message = match move_kind {
483
506
move_data:: Captured =>
484
507
format ! ( "cannot move `{}` into closure because it is borrowed" ,
485
- self . bccx. loan_path_to_str( & * * move_path) . as_slice( ) ) ,
508
+ self . bccx. loan_path_to_str( move_path) . as_slice( ) ) ,
486
509
move_data:: Declared |
487
510
move_data:: MoveExpr |
488
511
move_data:: MovePat =>
489
512
format ! ( "cannot move out of `{}` because it is borrowed" ,
490
- self . bccx. loan_path_to_str( & * * move_path) . as_slice( ) )
513
+ self . bccx. loan_path_to_str( move_path) . as_slice( ) )
491
514
} ;
492
515
493
516
self . bccx . span_err ( span, err_message. as_slice ( ) ) ;
@@ -500,6 +523,99 @@ impl<'a> CheckLoanCtxt<'a> {
500
523
}
501
524
}
502
525
526
+ pub fn analyze_restrictions_on_use ( & self ,
527
+ expr_id : ast:: NodeId ,
528
+ use_path : & LoanPath ,
529
+ borrow_kind : ty:: BorrowKind )
530
+ -> UseError {
531
+ debug ! ( "analyze_restrictions_on_use(expr_id={:?}, use_path={})" ,
532
+ self . tcx( ) . map. node_to_str( expr_id) ,
533
+ use_path. repr( self . tcx( ) ) ) ;
534
+
535
+ let mut ret = UseOk ;
536
+
537
+ // First, we check for a restriction on the path P being used. This
538
+ // accounts for borrows of P but also borrows of subpaths, like P.a.b.
539
+ // Consider the following example:
540
+ //
541
+ // let x = &mut a.b.c; // Restricts a, a.b, and a.b.c
542
+ // let y = a; // Conflicts with restriction
543
+
544
+ self . each_in_scope_restriction ( expr_id, use_path, |loan, _restr| {
545
+ if incompatible ( loan. kind , borrow_kind) {
546
+ ret = UseWhileBorrowed ( loan. loan_path . clone ( ) , loan. span ) ;
547
+ false
548
+ } else {
549
+ true
550
+ }
551
+ } ) ;
552
+
553
+ // Next, we must check for *loans* (not restrictions) on the path P or
554
+ // any base path. This rejects examples like the following:
555
+ //
556
+ // let x = &mut a.b;
557
+ // let y = a.b.c;
558
+ //
559
+ // Limiting this search to *loans* and not *restrictions* means that
560
+ // examples like the following continue to work:
561
+ //
562
+ // let x = &mut a.b;
563
+ // let y = a.c;
564
+
565
+ let mut loan_path = use_path;
566
+ loop {
567
+ self . each_in_scope_loan ( expr_id, |loan| {
568
+ if * loan. loan_path == * loan_path &&
569
+ incompatible ( loan. kind , borrow_kind) {
570
+ ret = UseWhileBorrowed ( loan. loan_path . clone ( ) , loan. span ) ;
571
+ false
572
+ } else {
573
+ true
574
+ }
575
+ } ) ;
576
+
577
+ match * loan_path {
578
+ LpVar ( _) => {
579
+ break ;
580
+ }
581
+ LpExtend ( ref lp_base, _, _) => {
582
+ loan_path = & * * lp_base;
583
+ }
584
+ }
585
+ }
586
+
587
+ return ret;
588
+
589
+ fn incompatible ( borrow_kind1 : ty:: BorrowKind ,
590
+ borrow_kind2 : ty:: BorrowKind )
591
+ -> bool {
592
+ borrow_kind1 != ty:: ImmBorrow || borrow_kind2 != ty:: ImmBorrow
593
+ }
594
+ }
595
+
596
+ fn check_if_path_is_moved ( & self ,
597
+ id : ast:: NodeId ,
598
+ span : Span ,
599
+ use_kind : MovedValueUseKind ,
600
+ lp : & Rc < LoanPath > ) {
601
+ /*!
602
+ * Reports an error if `expr` (which should be a path)
603
+ * is using a moved/uninitialized value
604
+ */
605
+
606
+ debug ! ( "check_if_path_is_moved(id={:?}, use_kind={:?}, lp={})" ,
607
+ id, use_kind, lp. repr( self . bccx. tcx) ) ;
608
+ self . move_data . each_move_of ( id, lp, |move, moved_lp| {
609
+ self . bccx . report_use_of_moved_value (
610
+ span,
611
+ use_kind,
612
+ & * * lp,
613
+ move ,
614
+ moved_lp) ;
615
+ false
616
+ } ) ;
617
+ }
618
+
503
619
fn check_if_assigned_path_is_moved ( & self ,
504
620
id : ast:: NodeId ,
505
621
span : Span ,
@@ -541,29 +657,6 @@ impl<'a> CheckLoanCtxt<'a> {
541
657
}
542
658
}
543
659
544
- fn check_if_path_is_moved ( & self ,
545
- id : ast:: NodeId ,
546
- span : Span ,
547
- use_kind : MovedValueUseKind ,
548
- lp : & Rc < LoanPath > ) {
549
- /*!
550
- * Reports an error if `expr` (which should be a path)
551
- * is using a moved/uninitialized value
552
- */
553
-
554
- debug ! ( "check_if_path_is_moved(id={:?}, use_kind={:?}, lp={})" ,
555
- id, use_kind, lp. repr( self . bccx. tcx) ) ;
556
- self . move_data . each_move_of ( id, lp, |move, moved_lp| {
557
- self . bccx . report_use_of_moved_value (
558
- span,
559
- use_kind,
560
- & * * lp,
561
- move ,
562
- moved_lp) ;
563
- false
564
- } ) ;
565
- }
566
-
567
660
fn check_assignment ( & self ,
568
661
assignment_id : ast:: NodeId ,
569
662
assignment_span : Span ,
@@ -862,35 +955,4 @@ impl<'a> CheckLoanCtxt<'a> {
862
955
format ! ( "borrow of `{}` occurs here" ,
863
956
self . bccx. loan_path_to_str( loan_path) ) . as_slice ( ) ) ;
864
957
}
865
-
866
- pub fn analyze_move_out_from ( & self ,
867
- expr_id : ast:: NodeId ,
868
- move_path : & LoanPath )
869
- -> MoveError {
870
- debug ! ( "analyze_move_out_from(expr_id={:?}, move_path={})" ,
871
- self . tcx( ) . map. node_to_str( expr_id) ,
872
- move_path. repr( self . tcx( ) ) ) ;
873
-
874
- // We must check every element of a move path. See
875
- // `borrowck-move-subcomponent.rs` for a test case.
876
-
877
- // check for a conflicting loan:
878
- let mut ret = MoveOk ;
879
- self . each_in_scope_restriction ( expr_id, move_path, |loan, _| {
880
- // Any restriction prevents moves.
881
- ret = MoveWhileBorrowed ( loan. loan_path . clone ( ) , loan. span ) ;
882
- false
883
- } ) ;
884
-
885
- if ret != MoveOk {
886
- return ret
887
- }
888
-
889
- match * move_path {
890
- LpVar ( _) => MoveOk ,
891
- LpExtend ( ref subpath, _, _) => {
892
- self . analyze_move_out_from ( expr_id, & * * subpath)
893
- }
894
- }
895
- }
896
958
}
0 commit comments