about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2013-05-03 16:26:43 -0400
committerNiko Matsakis <niko@alum.mit.edu>2013-05-03 16:27:16 -0400
commitbe08c3e5146953619ff777aaa422152dfee4ad28 (patch)
tree0dd6cad23983eaea96cf6718e3fa6d672e077469
parentf3a6ea26437e240b02d749331b3a2d60aab0588b (diff)
downloadrust-be08c3e5146953619ff777aaa422152dfee4ad28.tar.gz
rust-be08c3e5146953619ff777aaa422152dfee4ad28.zip
rustc: add rooting, write-guards to slices etc
-rw-r--r--src/librustc/middle/trans/_match.rs25
-rw-r--r--src/librustc/middle/trans/controlflow.rs2
-rw-r--r--src/librustc/middle/trans/datum.rs70
-rw-r--r--src/librustc/middle/trans/expr.rs19
-rw-r--r--src/test/run-fail/borrowck-wg-fail-2.rs3
-rw-r--r--src/test/run-fail/borrowck-wg-fail-3.rs3
-rw-r--r--src/test/run-fail/borrowck-wg-fail.rs3
-rw-r--r--src/test/run-fail/borrowck-wg-one-mut-one-imm-slice-method.rs37
-rw-r--r--src/test/run-fail/borrowck-wg-one-mut-one-imm-slices.rs16
-rw-r--r--src/test/run-fail/borrowck-wg-one-mut-one-imm.rs17
-rw-r--r--src/test/run-fail/borrowck-wg-two-array-indices.rs17
-rw-r--r--src/test/run-pass/borrowck-wg-two-imm-borrows.rs14
12 files changed, 194 insertions, 32 deletions
diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs
index 80e34ca4814..3b1cdf0ba47 100644
--- a/src/librustc/middle/trans/_match.rs
+++ b/src/librustc/middle/trans/_match.rs
@@ -866,7 +866,18 @@ pub fn extract_variant_args(bcx: block,
     ExtractedBlock { vals: args, bcx: bcx }
 }
 
+fn match_datum(bcx: block, val: ValueRef, pat_id: ast::node_id) -> Datum {
+    //! Helper for converting from the ValueRef that we pass around in
+    //! the match code, which is always by ref, into a Datum. Eventually
+    //! we should just pass around a Datum and be done with it.
+
+    let ty = node_id_type(bcx, pat_id);
+    Datum {val: val, ty: ty, mode: datum::ByRef, source: RevokeClean}
+}
+
+
 pub fn extract_vec_elems(bcx: block,
+                         pat_span: span,
                          pat_id: ast::node_id,
                          elem_count: uint,
                          slice: Option<uint>,
@@ -874,9 +885,9 @@ pub fn extract_vec_elems(bcx: block,
                          count: ValueRef)
                       -> ExtractedBlock {
     let _icx = bcx.insn_ctxt("match::extract_vec_elems");
+    let vec_datum = match_datum(bcx, val, pat_id);
+    let (bcx, base, len) = vec_datum.get_vec_base_and_len(bcx, pat_span, pat_id);
     let vt = tvec::vec_types(bcx, node_id_type(bcx, pat_id));
-    let unboxed = load_if_immediate(bcx, val, vt.vec_ty);
-    let (base, len) = tvec::get_base_and_len(bcx, unboxed, vt.vec_ty);
 
     let mut elems = do vec::from_fn(elem_count) |i| {
         match slice {
@@ -1308,10 +1319,14 @@ pub fn compile_submatch(bcx: block,
                                 vec::slice(vals, col + 1u, vals.len()));
     let ccx = *bcx.fcx.ccx;
     let mut pat_id = 0;
+    let mut pat_span = dummy_sp();
     for vec::each(m) |br| {
         // Find a real id (we're adding placeholder wildcard patterns, but
         // each column is guaranteed to have at least one real pattern)
-        if pat_id == 0 { pat_id = br.pats[col].id; }
+        if pat_id == 0 {
+            pat_id = br.pats[col].id;
+            pat_span = br.pats[col].span;
+        }
     }
 
     // If we are not matching against an `@T`, we should not be
@@ -1579,8 +1594,8 @@ pub fn compile_submatch(bcx: block,
                     vec_len_ge(_, i) => Some(i),
                     _ => None
                 };
-                let args = extract_vec_elems(opt_cx, pat_id, n, slice,
-                    val, test_val);
+                let args = extract_vec_elems(opt_cx, pat_span, pat_id, n, slice,
+                                             val, test_val);
                 size = args.vals.len();
                 unpacked = /*bad*/copy args.vals;
                 opt_cx = args.bcx;
diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs
index 60b6cf9e23f..c8699cc6371 100644
--- a/src/librustc/middle/trans/controlflow.rs
+++ b/src/librustc/middle/trans/controlflow.rs
@@ -333,7 +333,7 @@ pub fn trans_fail_expr(bcx: block,
                 bcx, expr::trans_to_datum(bcx, arg_expr));
 
             if ty::type_is_str(arg_datum.ty) {
-                let (lldata, _lllen) = arg_datum.get_base_and_len(bcx);
+                let (lldata, _) = arg_datum.get_vec_base_and_len_no_root(bcx);
                 return trans_fail_value(bcx, sp_opt, lldata);
             } else if bcx.unreachable || ty::type_is_bot(arg_datum.ty) {
                 return bcx;
diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs
index 095798ae212..6ffe504b804 100644
--- a/src/librustc/middle/trans/datum.rs
+++ b/src/librustc/middle/trans/datum.rs
@@ -603,6 +603,8 @@ pub impl Datum {
     }
 
     fn perform_write_guard(&self, bcx: block, span: span) -> block {
+        debug!("perform_write_guard");
+
         // Create scratch space, but do not root it.
         let llval = match self.mode {
             ByValue => self.val,
@@ -682,25 +684,10 @@ pub impl Datum {
     {
         let ccx = bcx.ccx();
 
-        debug!("try_deref(expr_id=%d, derefs=%?, is_auto=%b, self=%?)",
+        debug!("try_deref(expr_id=%?, derefs=%?, is_auto=%b, self=%?)",
                expr_id, derefs, is_auto, self.to_str(bcx.ccx()));
-        let _indenter = indenter();
-
-        // root the autoderef'd value, if necessary:
-        //
-        // (Note: root'd values are always boxes)
-        let key = root_map_key { id: expr_id, derefs: derefs };
-        let bcx = match ccx.maps.root_map.find(&key) {
-            None => bcx,
-            Some(&root_info) => self.root(bcx, span, key, root_info)
-        };
 
-        // Perform the write guard, if necessary.
-        //
-        // (Note: write-guarded values are always boxes)
-        let bcx = if ccx.maps.write_guard_map.contains(&key) {
-            self.perform_write_guard(bcx, span)
-        } else { bcx };
+        let bcx = self.root_and_write_guard(bcx, span, expr_id, derefs);
 
         match ty::get(self.ty).sty {
             ty::ty_box(_) | ty::ty_uniq(_) => {
@@ -854,8 +841,53 @@ pub impl Datum {
         DatumBlock { bcx: bcx, datum: datum }
     }
 
-    fn get_base_and_len(&self, bcx: block) -> (ValueRef, ValueRef) {
-        tvec::get_base_and_len(bcx, self.to_appropriate_llval(bcx), self.ty)
+    fn root_and_write_guard(&self,
+                            mut bcx: block,
+                            span: span,
+                            expr_id: ast::node_id,
+                            derefs: uint) -> block {
+        let key = root_map_key { id: expr_id, derefs: derefs };
+        debug!("root_and_write_guard(key=%?)", key);
+
+        // root the autoderef'd value, if necessary:
+        //
+        // (Note: root'd values are always boxes)
+        let ccx = bcx.ccx();
+        bcx = match ccx.maps.root_map.find(&key) {
+            None => bcx,
+            Some(&root_info) => self.root(bcx, span, key, root_info)
+        };
+
+        // Perform the write guard, if necessary.
+        //
+        // (Note: write-guarded values are always boxes)
+        if ccx.maps.write_guard_map.contains(&key) {
+            self.perform_write_guard(bcx, span)
+        } else {
+            bcx
+        }
+    }
+
+    fn get_vec_base_and_len(&self,
+                            mut bcx: block,
+                            span: span,
+                            expr_id: ast::node_id)
+                            -> (block, ValueRef, ValueRef) {
+        //! Converts a vector into the slice pair. Performs rooting
+        //! and write guards checks.
+
+        // only imp't for @[] and @str, but harmless
+        bcx = self.root_and_write_guard(bcx, span, expr_id, 0);
+        let (base, len) = self.get_vec_base_and_len_no_root(bcx);
+        (bcx, base, len)
+    }
+
+    fn get_vec_base_and_len_no_root(&self, bcx: block) -> (ValueRef, ValueRef) {
+        //! Converts a vector into the slice pair. Des not root
+        //! nor perform write guard checks.
+
+        let llval = self.to_appropriate_llval(bcx);
+        tvec::get_base_and_len(bcx, llval, self.ty)
     }
 
     fn to_result(&self, bcx: block) -> common::Result {
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index 1a9824dcfe8..b8cdfeb796d 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -218,10 +218,10 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
                     unpack_datum!(bcx, auto_ref(bcx, datum))
                 }
                 Some(AutoBorrowVec(*)) => {
-                    unpack_datum!(bcx, auto_slice(bcx, datum))
+                    unpack_datum!(bcx, auto_slice(bcx, expr, datum))
                 }
                 Some(AutoBorrowVecRef(*)) => {
-                    unpack_datum!(bcx, auto_slice_and_ref(bcx, datum))
+                    unpack_datum!(bcx, auto_slice_and_ref(bcx, expr, datum))
                 }
                 Some(AutoBorrowFn(*)) => {
                     // currently, all closure types are
@@ -241,7 +241,7 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
         DatumBlock {bcx: bcx, datum: datum.to_rptr(bcx)}
     }
 
-    fn auto_slice(bcx: block, datum: Datum) -> DatumBlock {
+    fn auto_slice(bcx: block, expr: @ast::expr, datum: Datum) -> DatumBlock {
         // This is not the most efficient thing possible; since slices
         // are two words it'd be better if this were compiled in
         // 'dest' mode, but I can't find a nice way to structure the
@@ -250,7 +250,9 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
 
         let tcx = bcx.tcx();
         let unit_ty = ty::sequence_element_type(tcx, datum.ty);
-        let (base, len) = datum.get_base_and_len(bcx);
+        // NOTE prob need to distinguish "auto-slice" from explicit index?
+        let (bcx, base, len) =
+            datum.get_vec_base_and_len(bcx, expr.span, expr.id);
 
         // this type may have a different region/mutability than the
         // real one, but it will have the same runtime representation
@@ -283,8 +285,10 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
         DatumBlock {bcx: bcx, datum: scratch}
     }
 
-    fn auto_slice_and_ref(bcx: block, datum: Datum) -> DatumBlock {
-        let DatumBlock { bcx, datum } = auto_slice(bcx, datum);
+    fn auto_slice_and_ref(bcx: block,
+                          expr: @ast::expr,
+                          datum: Datum) -> DatumBlock {
+        let DatumBlock { bcx, datum } = auto_slice(bcx, expr, datum);
         auto_ref(bcx, datum)
     }
 }
@@ -903,7 +907,8 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
         let scaled_ix = Mul(bcx, ix_val, vt.llunit_size);
         base::maybe_name_value(bcx.ccx(), scaled_ix, ~"scaled_ix");
 
-        let mut (base, len) = base_datum.get_base_and_len(bcx);
+        let mut (bcx, base, len) =
+            base_datum.get_vec_base_and_len(bcx, index_expr.span, index_expr.id);
 
         if ty::type_is_str(base_ty) {
             // acccount for null terminator in the case of string
diff --git a/src/test/run-fail/borrowck-wg-fail-2.rs b/src/test/run-fail/borrowck-wg-fail-2.rs
index 121ec9c7921..59a5fecd340 100644
--- a/src/test/run-fail/borrowck-wg-fail-2.rs
+++ b/src/test/run-fail/borrowck-wg-fail-2.rs
@@ -1,5 +1,8 @@
 // error-pattern:borrowed
 
+// Test that write guards trigger when there is a write to a field
+// of a frozen structure.
+
 struct S {
     x: int
 }
diff --git a/src/test/run-fail/borrowck-wg-fail-3.rs b/src/test/run-fail/borrowck-wg-fail-3.rs
index 2b95cf3fe5f..ebff553aafb 100644
--- a/src/test/run-fail/borrowck-wg-fail-3.rs
+++ b/src/test/run-fail/borrowck-wg-fail-3.rs
@@ -1,5 +1,8 @@
 // error-pattern:borrowed
 
+// Test that write guards trigger when there is a write to a directly
+// frozen @mut box.
+
 fn main() {
     let x = @mut 3;
     let y: &mut int = x;
diff --git a/src/test/run-fail/borrowck-wg-fail.rs b/src/test/run-fail/borrowck-wg-fail.rs
index fd2d36b895a..939d802c21c 100644
--- a/src/test/run-fail/borrowck-wg-fail.rs
+++ b/src/test/run-fail/borrowck-wg-fail.rs
@@ -1,5 +1,8 @@
 // error-pattern:borrowed
 
+// Test that write guards trigger when mut box is frozen
+// as part of argument coercion.
+
 fn f(_x: &int, y: @mut int) {
     *y = 2;
 }
diff --git a/src/test/run-fail/borrowck-wg-one-mut-one-imm-slice-method.rs b/src/test/run-fail/borrowck-wg-one-mut-one-imm-slice-method.rs
new file mode 100644
index 00000000000..91df90f8b3a
--- /dev/null
+++ b/src/test/run-fail/borrowck-wg-one-mut-one-imm-slice-method.rs
@@ -0,0 +1,37 @@
+// error-pattern:borrowed
+
+// Test that write guards trigger when there is a coercion to
+// a slice on the receiver of a method.
+
+trait MyMutSlice {
+    fn my_mut_slice(self) -> Self;
+}
+
+impl<'self, T> MyMutSlice for &'self mut [T] {
+    fn my_mut_slice(self) -> &'self mut [T] {
+        self
+    }
+}
+
+trait MySlice {
+    fn my_slice(self) -> Self;
+}
+
+impl<'self, T> MySlice for &'self [T] {
+    fn my_slice(self) -> &'self [T] {
+        self
+    }
+}
+
+fn add(x:&mut [int], y:&[int])
+{
+    x[0] = x[0] + y[0];
+}
+
+pub fn main()
+{
+    let z = @mut [1,2,3];
+    let z2 = z;
+    add(z.my_mut_slice(), z2.my_slice());
+    print(fmt!("%d\n", z[0]));
+}
diff --git a/src/test/run-fail/borrowck-wg-one-mut-one-imm-slices.rs b/src/test/run-fail/borrowck-wg-one-mut-one-imm-slices.rs
new file mode 100644
index 00000000000..bae693ce4ea
--- /dev/null
+++ b/src/test/run-fail/borrowck-wg-one-mut-one-imm-slices.rs
@@ -0,0 +1,16 @@
+// error-pattern:borrowed
+
+// Test that write guards trigger when arguments are coerced to slices.
+
+fn add(x:&mut [int], y:&[int])
+{
+    x[0] = x[0] + y[0];
+}
+
+pub fn main()
+{
+    let z = @mut [1,2,3];
+    let z2 = z;
+    add(z, z2);
+    print(fmt!("%d\n", z[0]));
+}
diff --git a/src/test/run-fail/borrowck-wg-one-mut-one-imm.rs b/src/test/run-fail/borrowck-wg-one-mut-one-imm.rs
new file mode 100644
index 00000000000..9e2a02b32df
--- /dev/null
+++ b/src/test/run-fail/borrowck-wg-one-mut-one-imm.rs
@@ -0,0 +1,17 @@
+// error-pattern:borrowed
+
+// Test that write guards trigger when we are indexing into
+// an @mut vector.
+
+fn add(x:&mut int, y:&int)
+{
+    *x = *x + *y;
+}
+
+pub fn main()
+{
+    let z = @mut [1,2,3];
+    let z2 = z;
+    add(&mut z[0], &z2[0]);
+    print(fmt!("%d\n", z[0]));
+}
diff --git a/src/test/run-fail/borrowck-wg-two-array-indices.rs b/src/test/run-fail/borrowck-wg-two-array-indices.rs
new file mode 100644
index 00000000000..ad684488760
--- /dev/null
+++ b/src/test/run-fail/borrowck-wg-two-array-indices.rs
@@ -0,0 +1,17 @@
+// error-pattern:borrowed
+
+// Test that arguments trigger when there are *two mutable* borrows
+// of indices.
+
+fn add(x:&mut int, y:&mut int)
+{
+    *x = *x + *y;
+}
+
+pub fn main()
+{
+    let z = @mut [1,2,3];
+    let z2 = z;
+    add(&mut z[0], &mut z2[0]);
+    print(fmt!("%d\n", z[0]));
+}
diff --git a/src/test/run-pass/borrowck-wg-two-imm-borrows.rs b/src/test/run-pass/borrowck-wg-two-imm-borrows.rs
new file mode 100644
index 00000000000..20f824e969a
--- /dev/null
+++ b/src/test/run-pass/borrowck-wg-two-imm-borrows.rs
@@ -0,0 +1,14 @@
+// Test that we can borrow the same @mut box twice, so long as both are imm.
+
+fn add(x:&int, y:&int)
+{
+    *x + *y;
+}
+
+pub fn main()
+{
+    let z = @mut [1,2,3];
+    let z2 = z;
+    add(&z[0], &z2[0]);
+    print(fmt!("%d\n", z[0]));
+}