diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index 24bd675fac28e..a9eec53fd94b2 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -15,6 +15,7 @@ use rustc::hir; use rustc::mir::{Mir, Place}; use rustc::mir::{Projection, ProjectionElem}; use rustc::ty::{self, TyCtxt}; +use std::cmp::max; pub(super) fn places_conflict<'gcx, 'tcx>( tcx: TyCtxt<'_, 'gcx, 'tcx>, @@ -394,27 +395,78 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>( | (ProjectionElem::Index(..), ProjectionElem::ConstantIndex { .. }) | (ProjectionElem::Index(..), ProjectionElem::Subslice { .. }) | (ProjectionElem::ConstantIndex { .. }, ProjectionElem::Index(..)) - | (ProjectionElem::ConstantIndex { .. }, ProjectionElem::ConstantIndex { .. }) - | (ProjectionElem::ConstantIndex { .. }, ProjectionElem::Subslice { .. }) - | (ProjectionElem::Subslice { .. }, ProjectionElem::Index(..)) - | (ProjectionElem::Subslice { .. }, ProjectionElem::ConstantIndex { .. }) - | (ProjectionElem::Subslice { .. }, ProjectionElem::Subslice { .. }) => { + | (ProjectionElem::Subslice { .. }, ProjectionElem::Index(..)) => { // Array indexes (`a[0]` vs. `a[i]`). These can either be disjoint // (if the indexes differ) or equal (if they are the same), so this // is the recursive case that gives "equal *or* disjoint" its meaning. - // - // Note that by construction, MIR at borrowck can't subdivide - // `Subslice` accesses (e.g. `a[2..3][i]` will never be present) - they - // are only present in slice patterns, and we "merge together" nested - // slice patterns. That means we don't have to think about these. It's - // probably a good idea to assert this somewhere, but I'm too lazy. - // - // FIXME(#8636) we might want to return Disjoint if - // both projections are constant and disjoint. - debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY"); + debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX"); Overlap::EqualOrDisjoint } - + (ProjectionElem::ConstantIndex { offset: o1, min_length: _, from_end: false }, + ProjectionElem::ConstantIndex { offset: o2, min_length: _, from_end: false }) + | (ProjectionElem::ConstantIndex { offset: o1, min_length: _, from_end: true }, + ProjectionElem::ConstantIndex { + offset: o2, min_length: _, from_end: true }) => { + if o1 == o2 { + debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX"); + Overlap::EqualOrDisjoint + } else { + debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX"); + Overlap::Disjoint + } + } + (ProjectionElem::ConstantIndex { + offset: offset_from_begin, min_length: min_length1, from_end: false }, + ProjectionElem::ConstantIndex { + offset: offset_from_end, min_length: min_length2, from_end: true }) + | (ProjectionElem::ConstantIndex { + offset: offset_from_end, min_length: min_length1, from_end: true }, + ProjectionElem::ConstantIndex { + offset: offset_from_begin, min_length: min_length2, from_end: false }) => { + // both patterns matched so it must be at least the greater of the two + let min_length = max(min_length1, min_length2); + // `offset_from_end` can be in range `[1..min_length]`, 1 indicates the last + // element (like -1 in Python) and `min_length` the first. + // Therefore, `min_length - offset_from_end` gives the minimal possible + // offset from the beginning + if *offset_from_begin >= min_length - offset_from_end { + debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE"); + Overlap::EqualOrDisjoint + } else { + debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-FE"); + Overlap::Disjoint + } + } + (ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }, + ProjectionElem::Subslice {from, .. }) + | (ProjectionElem::Subslice {from, .. }, + ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }) => { + if offset >= from { + debug!( + "place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE"); + Overlap::EqualOrDisjoint + } else { + debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE"); + Overlap::Disjoint + } + } + (ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }, + ProjectionElem::Subslice {from: _, to }) + | (ProjectionElem::Subslice {from: _, to }, + ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }) => { + if offset > to { + debug!("place_element_conflict: \ + DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE-FE"); + Overlap::EqualOrDisjoint + } else { + debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE-FE"); + Overlap::Disjoint + } + } + (ProjectionElem::Subslice { .. }, ProjectionElem::Subslice { .. }) => { + debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES"); + Overlap::EqualOrDisjoint + } (ProjectionElem::Deref, _) | (ProjectionElem::Field(..), _) | (ProjectionElem::Index(..), _) diff --git a/src/test/run-pass/borrowck/borrowck-slice-pattern-element-loan.rs b/src/test/run-pass/borrowck/borrowck-slice-pattern-element-loan.rs new file mode 100644 index 0000000000000..48d16102ff3c2 --- /dev/null +++ b/src/test/run-pass/borrowck/borrowck-slice-pattern-element-loan.rs @@ -0,0 +1,33 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//compile-flags: -Z borrowck=mir + +#![feature(slice_patterns)] + +fn mut_head_tail<'a, A>(v: &'a mut [A]) -> Option<(&'a mut A, &'a mut [A])> { + match *v { + [ref mut head, ref mut tail..] => { + Some((head, tail)) + } + [] => None + } +} + +fn main() { + let mut v = [1,2,3,4]; + match mut_head_tail(&mut v) { + None => {}, + Some((h,t)) => { + *h = 1000; + t.reverse(); + } + } +} diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.rs b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.rs new file mode 100644 index 0000000000000..da36f494eb686 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.rs @@ -0,0 +1,137 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//compile-flags: -Z borrowck=mir + +#![feature(slice_patterns)] + +fn nop(_s: &[& i32]) {} +fn nop_subslice(_s: &[i32]) {} + +fn const_index_ok(s: &mut [i32]) { + if let [ref first, ref second, _, ref fourth, ..] = *s { + if let [_, _, ref mut third, ..] = *s { + nop(&[first, second, third, fourth]); + } + } +} + +fn const_index_err(s: &mut [i32]) { + if let [ref first, ref second, ..] = *s { + if let [_, ref mut second2, ref mut third, ..] = *s { //~ERROR + nop(&[first, second, second2, third]); + } + } +} + +fn const_index_from_end_ok(s: &mut [i32]) { + if let [.., ref fourth, ref third, _, ref first] = *s { + if let [.., ref mut second, _] = *s { + nop(&[first, second, third, fourth]); + } + } +} + +fn const_index_from_end_err(s: &mut [i32]) { + if let [.., ref fourth, ref third, _, ref first] = *s { + if let [.., ref mut third2, _, _] = *s { //~ERROR + nop(&[first, third, third2, fourth]); + } + } +} + +fn const_index_mixed(s: &mut [i32]) { + if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s { + if let [ref mut from_begin0, ..] = *s { + nop(&[from_begin0, from_end1, from_end3, from_end4]); + } + if let [_, ref mut from_begin1, ..] = *s { //~ERROR + nop(&[from_begin1, from_end1, from_end3, from_end4]); + } + if let [_, _, ref mut from_begin2, ..] = *s { //~ERROR + nop(&[from_begin2, from_end1, from_end3, from_end4]); + } + if let [_, _, _, ref mut from_begin3, ..] = *s { //~ERROR + nop(&[from_begin3, from_end1, from_end3, from_end4]); + } + } + if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s { + if let [.., ref mut from_end1] = *s { + nop(&[from_begin0, from_begin1, from_begin3, from_end1]); + } + if let [.., ref mut from_end2, _] = *s { //~ERROR + nop(&[from_begin0, from_begin1, from_begin3, from_end2]); + } + if let [.., ref mut from_end3, _, _] = *s { //~ERROR + nop(&[from_begin0, from_begin1, from_begin3, from_end3]); + } + if let [.., ref mut from_end4, _, _, _] = *s { //~ERROR + nop(&[from_begin0, from_begin1, from_begin3, from_end4]); + } + } +} + +fn const_index_and_subslice_ok(s: &mut [i32]) { + if let [ref first, ref second, ..] = *s { + if let [_, _, ref mut tail..] = *s { + nop(&[first, second]); + nop_subslice(tail); + } + } +} + +fn const_index_and_subslice_err(s: &mut [i32]) { + if let [ref first, ref second, ..] = *s { + if let [_, ref mut tail..] = *s { //~ERROR + nop(&[first, second]); + nop_subslice(tail); + } + } +} + +fn const_index_and_subslice_from_end_ok(s: &mut [i32]) { + if let [.., ref second, ref first] = *s { + if let [ref mut tail.., _, _] = *s { + nop(&[first, second]); + nop_subslice(tail); + } + } +} + +fn const_index_and_subslice_from_end_err(s: &mut [i32]) { + if let [.., ref second, ref first] = *s { + if let [ref mut tail.., _] = *s { //~ERROR + nop(&[first, second]); + nop_subslice(tail); + } + } +} + +fn subslices(s: &mut [i32]) { + if let [_, _, _, ref s1..] = *s { + if let [ref mut s2.., _, _, _] = *s { //~ERROR + nop_subslice(s1); + nop_subslice(s2); + } + } +} + +fn main() { + let mut v = [1,2,3,4]; + const_index_ok(&mut v); + const_index_err(&mut v); + const_index_from_end_ok(&mut v); + const_index_from_end_err(&mut v); + const_index_and_subslice_ok(&mut v); + const_index_and_subslice_err(&mut v); + const_index_and_subslice_from_end_ok(&mut v); + const_index_and_subslice_from_end_err(&mut v); + subslices(&mut v); +} diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.stderr b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.stderr new file mode 100644 index 0000000000000..16d401ec7f9bf --- /dev/null +++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.stderr @@ -0,0 +1,119 @@ +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan.rs:28:20 + | +LL | if let [ref first, ref second, ..] = *s { + | ---------- immutable borrow occurs here +LL | if let [_, ref mut second2, ref mut third, ..] = *s { //~ERROR + | ^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[first, second, second2, third]); + | ------ borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan.rs:44:21 + | +LL | if let [.., ref fourth, ref third, _, ref first] = *s { + | --------- immutable borrow occurs here +LL | if let [.., ref mut third2, _, _] = *s { //~ERROR + | ^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[first, third, third2, fourth]); + | ----- borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan.rs:55:20 + | +LL | if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s { + | ------------- immutable borrow occurs here +... +LL | if let [_, ref mut from_begin1, ..] = *s { //~ERROR + | ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[from_begin1, from_end1, from_end3, from_end4]); + | --------- borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan.rs:58:23 + | +LL | if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s { + | ------------- immutable borrow occurs here +... +LL | if let [_, _, ref mut from_begin2, ..] = *s { //~ERROR + | ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[from_begin2, from_end1, from_end3, from_end4]); + | --------- borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan.rs:61:26 + | +LL | if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s { + | ------------- immutable borrow occurs here +... +LL | if let [_, _, _, ref mut from_begin3, ..] = *s { //~ERROR + | ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[from_begin3, from_end1, from_end3, from_end4]); + | --------- borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan.rs:69:21 + | +LL | if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s { + | --------------- immutable borrow occurs here +... +LL | if let [.., ref mut from_end2, _] = *s { //~ERROR + | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[from_begin0, from_begin1, from_begin3, from_end2]); + | ----------- borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan.rs:72:21 + | +LL | if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s { + | --------------- immutable borrow occurs here +... +LL | if let [.., ref mut from_end3, _, _] = *s { //~ERROR + | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[from_begin0, from_begin1, from_begin3, from_end3]); + | ----------- borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan.rs:75:21 + | +LL | if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s { + | --------------- immutable borrow occurs here +... +LL | if let [.., ref mut from_end4, _, _, _] = *s { //~ERROR + | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[from_begin0, from_begin1, from_begin3, from_end4]); + | ----------- borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan.rs:92:20 + | +LL | if let [ref first, ref second, ..] = *s { + | ---------- immutable borrow occurs here +LL | if let [_, ref mut tail..] = *s { //~ERROR + | ^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[first, second]); + | ------ borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan.rs:110:17 + | +LL | if let [.., ref second, ref first] = *s { + | ---------- immutable borrow occurs here +LL | if let [ref mut tail.., _] = *s { //~ERROR + | ^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[first, second]); + | ------ borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan.rs:119:17 + | +LL | if let [_, _, _, ref s1..] = *s { + | ------ immutable borrow occurs here +LL | if let [ref mut s2.., _, _, _] = *s { //~ERROR + | ^^^^^^^^^^ mutable borrow occurs here +LL | nop_subslice(s1); + | -- borrow later used here + +error: aborting due to 11 previous errors + +For more information about this error, try `rustc --explain E0502`.