@@ -150,9 +150,9 @@ pub fn check_loans(bccx: &BorrowckCtxt,
150150}
151151
152152#[ 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 )
156156}
157157
158158impl < ' a > CheckLoanCtxt < ' a > {
@@ -438,8 +438,7 @@ impl<'a> CheckLoanCtxt<'a> {
438438 Some ( lp) => {
439439 let moved_value_use_kind = match mode {
440440 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) ;
443442 MovedInUse
444443 }
445444 euv:: Move ( _) => {
@@ -454,7 +453,7 @@ impl<'a> CheckLoanCtxt<'a> {
454453 }
455454 Some ( move_kind) => {
456455 self . check_for_move_of_borrowed_path ( id, span,
457- & lp, move_kind) ;
456+ & * lp, move_kind) ;
458457 if move_kind == move_data:: Captured {
459458 MovedInCapture
460459 } else {
@@ -471,23 +470,47 @@ impl<'a> CheckLoanCtxt<'a> {
471470 }
472471 }
473472
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+
474494 fn check_for_move_of_borrowed_path ( & self ,
475495 id : ast:: NodeId ,
476496 span : Span ,
477- move_path : & Rc < LoanPath > ,
497+ move_path : & LoanPath ,
478498 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) => {
482505 let err_message = match move_kind {
483506 move_data:: Captured =>
484507 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( ) ) ,
486509 move_data:: Declared |
487510 move_data:: MoveExpr |
488511 move_data:: MovePat =>
489512 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( ) )
491514 } ;
492515
493516 self . bccx . span_err ( span, err_message. as_slice ( ) ) ;
@@ -500,6 +523,99 @@ impl<'a> CheckLoanCtxt<'a> {
500523 }
501524 }
502525
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+
503619 fn check_if_assigned_path_is_moved ( & self ,
504620 id : ast:: NodeId ,
505621 span : Span ,
@@ -541,29 +657,6 @@ impl<'a> CheckLoanCtxt<'a> {
541657 }
542658 }
543659
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-
567660 fn check_assignment ( & self ,
568661 assignment_id : ast:: NodeId ,
569662 assignment_span : Span ,
@@ -862,35 +955,4 @@ impl<'a> CheckLoanCtxt<'a> {
862955 format ! ( "borrow of `{}` occurs here" ,
863956 self . bccx. loan_path_to_str( loan_path) ) . as_slice ( ) ) ;
864957 }
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- }
896958}
0 commit comments