about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2016-07-24 13:56:27 +0300
committerAriel Ben-Yehuda <arielb1@mail.tau.ac.il>2016-09-16 15:08:32 +0300
commit7b25e886028195a4f90c0baa5cc9101ebeceb5a3 (patch)
tree7899d0115549790a45f227311015fe4733c9ca86 /src
parenteb19cd65756cd285c81410e627752a75a41e3f0e (diff)
downloadrust-7b25e886028195a4f90c0baa5cc9101ebeceb5a3.tar.gz
rust-7b25e886028195a4f90c0baa5cc9101ebeceb5a3.zip
forbid moves out of slices
The wording of RFC #495 enables moves out of slices. Unfortuantely, non-zeroing
moves out of slices introduce a very annoying complication: as slices can
vary in their length, indexes from the start and end may or may not overlap
depending on the slice's exact length, which prevents assigning a particular
drop flag for each individual element.

For example, in the code

```Rust
fn foo<T>(a: Box<[Box<[T]>]>, c: bool) -> T {
    match (a, c) {
        (box [box [t, ..], ..], true) => t,
        (box [.., box [.., t]], false) => t,
        _ => panic!()
    }
}
```

If the condition is false, we have to drop the first element
of `a`, unless `a` has size 1 in which case we drop all the elements
of it but the last.

If someone comes with a nice way of handling it, we can always re-allow
moves out of slices.

This is a [breaking-change], but it is behind the `slice_patterns` feature
gate and was not allowed until recently.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs1
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/move_error.rs26
-rw-r--r--src/test/compile-fail/move-out-of-slice-1.rs21
3 files changed, 36 insertions, 12 deletions
diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
index 3e335dacc8e..9bdc6887f6d 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
@@ -185,6 +185,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                         check_and_get_illegal_move_origin(bccx, b)
                     }
                 }
+                ty::TySlice(..) => Some(cmt.clone()),
                 _ => {
                     check_and_get_illegal_move_origin(bccx, b)
                 }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
index 3fa7c252b84..9fbf1492f5d 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
@@ -16,7 +16,6 @@ use rustc::ty;
 use syntax::ast;
 use syntax_pos;
 use errors::DiagnosticBuilder;
-use rustc::hir;
 
 pub struct MoveErrorCollector<'tcx> {
     errors: Vec<MoveError<'tcx>>
@@ -131,17 +130,20 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
             err
         }
 
-        Categorization::Interior(ref b, mc::InteriorElement(Kind::Index, _)) => {
-            let expr = bccx.tcx.map.expect_expr(move_from.id);
-            if let hir::ExprIndex(..) = expr.node {
-                let mut err = struct_span_err!(bccx, move_from.span, E0508,
-                                               "cannot move out of type `{}`, \
-                                               a non-copy fixed-size array",
-                                               b.ty);
-                err.span_label(move_from.span, &format!("cannot move out of here"));
-                err
-            } else {
-                span_bug!(move_from.span, "this path should not cause illegal move");
+        Categorization::Interior(ref b, mc::InteriorElement(ik, _)) => {
+            match (&b.ty.sty, ik) {
+                (&ty::TySlice(..), _) |
+                (_, Kind::Index) => {
+                    let mut err = struct_span_err!(bccx, move_from.span, E0508,
+                                                   "cannot move out of type `{}`, \
+                                                    a non-copy array",
+                                                   b.ty);
+                    err.span_label(move_from.span, &format!("cannot move out of here"));
+                    err
+                }
+                (_, Kind::Pattern) => {
+                    span_bug!(move_from.span, "this path should not cause illegal move");
+                }
             }
         }
 
diff --git a/src/test/compile-fail/move-out-of-slice-1.rs b/src/test/compile-fail/move-out-of-slice-1.rs
new file mode 100644
index 00000000000..f3efc68701e
--- /dev/null
+++ b/src/test/compile-fail/move-out-of-slice-1.rs
@@ -0,0 +1,21 @@
+// Copyright 2016 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(slice_patterns, box_patterns)]
+
+struct A;
+
+fn main() {
+    let a: Box<[A]> = Box::new([A]);
+    match a {
+        box [a] => {}, //~ ERROR cannot move out of type `[A]`
+        _ => {}
+    }
+}