]> git.lizzy.rs Git - rust.git/commitdiff
Reject double moves out of array elements
authorCameron Zwarich <zwarich@mozilla.com>
Wed, 18 Jun 2014 07:06:39 +0000 (00:06 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Thu, 19 Jun 2014 00:01:50 +0000 (17:01 -0700)
Fixes #14986.

src/librustc/middle/borrowck/move_data.rs
src/test/compile-fail/borrowck-array-double-move.rs [new file with mode: 0644]

index bb92043b1ea6a42e7a99dd7725fbd4070a28a922..9c2194c74f4a4a407a05b84451296d83136e2a25 100644 (file)
@@ -25,6 +25,7 @@
 use middle::dataflow::BitwiseOperator;
 use middle::dataflow::DataFlowOperator;
 use euv = middle::expr_use_visitor;
+use mc = middle::mem_categorization;
 use middle::ty;
 use syntax::ast;
 use syntax::ast_util;
@@ -160,6 +161,22 @@ pub struct Assignment {
 
 pub type AssignDataFlow<'a> = DataFlowContext<'a, AssignDataFlowOperator>;
 
+fn loan_path_is_precise(loan_path: &LoanPath) -> bool {
+    match *loan_path {
+        LpVar(_) => {
+            true
+        }
+        LpExtend(_, _, LpInterior(mc::InteriorElement(_))) => {
+            // Paths involving element accesses do not refer to a unique
+            // location, as there is no accurate tracking of the indices.
+            false
+        }
+        LpExtend(ref lp_base, _, _) => {
+            loan_path_is_precise(&**lp_base)
+        }
+    }
+}
+
 impl MoveData {
     pub fn new() -> MoveData {
         MoveData {
@@ -500,10 +517,17 @@ fn kill_moves(&self,
                   path: MovePathIndex,
                   kill_id: ast::NodeId,
                   dfcx_moves: &mut MoveDataFlow) {
-        self.each_applicable_move(path, |move_index| {
-            dfcx_moves.add_kill(kill_id, move_index.get());
-            true
-        });
+        // We can only perform kills for paths that refer to a unique location,
+        // since otherwise we may kill a move from one location with an
+        // assignment referring to another location.
+
+        let loan_path = self.path_loan_path(path);
+        if loan_path_is_precise(&*loan_path) {
+            self.each_applicable_move(path, |move_index| {
+                dfcx_moves.add_kill(kill_id, move_index.get());
+                true
+            });
+        }
     }
 }
 
diff --git a/src/test/compile-fail/borrowck-array-double-move.rs b/src/test/compile-fail/borrowck-array-double-move.rs
new file mode 100644 (file)
index 0000000..c7fb646
--- /dev/null
@@ -0,0 +1,21 @@
+// 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 <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.
+
+fn f() {
+    let mut a = [box 0, box 1];
+    drop(a[0]);
+    a[1] = box 2;
+    drop(a[0]); //~ ERROR use of moved value: `a[..]`
+}
+
+fn main() {
+    f();
+}
+