@@ -367,7 +367,6 @@ impl<'self> CheckLoanCtxt<'self> {
367367
368368 mc:: cat_rvalue( * ) |
369369 mc:: cat_static_item |
370- mc:: cat_implicit_self |
371370 mc:: cat_copied_upvar( * ) |
372371 mc:: cat_deref( _, _, mc:: unsafe_ptr( * ) ) |
373372 mc:: cat_deref( _, _, mc:: gc_ptr( * ) ) |
@@ -406,15 +405,7 @@ impl<'self> CheckLoanCtxt<'self> {
406405 mc:: cat_deref( b, _, mc:: region_ptr( m_mutbl, _) ) => {
407406 // Statically prohibit writes to `&mut` when aliasable
408407
409- match b. freely_aliasable ( ) {
410- None => { }
411- Some ( cause) => {
412- this. bccx . report_aliasability_violation (
413- expr. span ,
414- MutabilityViolation ,
415- cause) ;
416- }
417- }
408+ check_for_aliasability_violation ( this, expr, b) ;
418409 }
419410
420411 mc:: cat_deref( _, deref_count, mc:: gc_ptr( ast:: m_mutbl) ) => {
@@ -434,6 +425,51 @@ impl<'self> CheckLoanCtxt<'self> {
434425 return true ; // no errors reported
435426 }
436427
428+ fn check_for_aliasability_violation ( this : & CheckLoanCtxt ,
429+ expr : @ast:: expr ,
430+ cmt : mc:: cmt ) -> bool {
431+ let mut cmt = cmt;
432+
433+ loop {
434+ match cmt. cat {
435+ mc:: cat_deref( b, _, mc:: region_ptr( m_mutbl, _) ) |
436+ mc:: cat_downcast( b) |
437+ mc:: cat_stack_upvar( b) |
438+ mc:: cat_deref( b, _, mc:: uniq_ptr) |
439+ mc:: cat_interior( b, _) |
440+ mc:: cat_discr( b, _) => {
441+ // Aliasability depends on base cmt
442+ cmt = b;
443+ }
444+
445+ mc:: cat_copied_upvar( _) |
446+ mc:: cat_rvalue( * ) |
447+ mc:: cat_local( * ) |
448+ mc:: cat_arg( _) |
449+ mc:: cat_self( * ) |
450+ mc:: cat_deref( _, _, mc:: unsafe_ptr( * ) ) |
451+ mc:: cat_static_item( * ) |
452+ mc:: cat_deref( _, _, mc:: gc_ptr( _) ) |
453+ mc:: cat_deref( _, _, mc:: region_ptr( m_const, _) ) |
454+ mc:: cat_deref( _, _, mc:: region_ptr( m_imm, _) ) => {
455+ // Aliasability is independent of base cmt
456+ match cmt. freely_aliasable ( ) {
457+ None => {
458+ return true ;
459+ }
460+ Some ( cause) => {
461+ this. bccx . report_aliasability_violation (
462+ expr. span ,
463+ MutabilityViolation ,
464+ cause) ;
465+ return false ;
466+ }
467+ }
468+ }
469+ }
470+ }
471+ }
472+
437473 fn check_for_assignment_to_restricted_or_frozen_location (
438474 this : & CheckLoanCtxt ,
439475 expr : @ast:: expr ,
@@ -511,6 +547,12 @@ impl<'self> CheckLoanCtxt<'self> {
511547 // path, and check that the super path was not lent out as
512548 // mutable or immutable (a const loan is ok).
513549 //
550+ // Mutability of a path can be dependent on the super path
551+ // in two ways. First, it might be inherited mutability.
552+ // Second, the pointee of an `&mut` pointer can only be
553+ // mutated if it is found in an unaliased location, so we
554+ // have to check that the owner location is not borrowed.
555+ //
514556 // Note that we are *not* checking for any and all
515557 // restrictions. We are only interested in the pointers
516558 // that the user created, whereas we add restrictions for
@@ -528,9 +570,12 @@ impl<'self> CheckLoanCtxt<'self> {
528570 let mut loan_path = loan_path;
529571 loop {
530572 match * loan_path {
531- // Peel back one layer if `loan_path` has
532- // inherited mutability
533- LpExtend ( lp_base, mc:: McInherited , _) => {
573+ // Peel back one layer if, for `loan_path` to be
574+ // mutable, `lp_base` must be mutable. This occurs
575+ // with inherited mutability and with `&mut`
576+ // pointers.
577+ LpExtend ( lp_base, mc:: McInherited , _) |
578+ LpExtend ( lp_base, _, LpDeref ( mc:: region_ptr( ast:: m_mutbl, _) ) ) => {
534579 loan_path = lp_base;
535580 }
536581
0 commit comments