From 17b3712487a4cf2be30e6bd43e89a736a7d86908 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 20 Jun 2013 15:11:20 -0400 Subject: [PATCH 01/20] Update existing tests to account for stricter, more correct handling of irrefutable patterns --- .../borrowck-move-out-of-vec-tail.rs | 2 +- .../borrowck-vec-pattern-nesting.rs | 37 +++++++++++++++++++ .../run-pass/borrowck-newtype-issue-2573.rs | 32 ---------------- ...f-and-autoborrowvec-combined-issue-6272.rs | 12 +++--- src/test/run-pass/match-pattern-drop.rs | 4 +- src/test/run-pass/vec-tail-matching.rs | 2 +- 6 files changed, 48 insertions(+), 41 deletions(-) delete mode 100644 src/test/run-pass/borrowck-newtype-issue-2573.rs diff --git a/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs b/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs index dec976e0a6068..91a3d843cd4ac 100644 --- a/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs +++ b/src/test/compile-fail/borrowck-move-out-of-vec-tail.rs @@ -11,7 +11,7 @@ pub fn main() { Foo { string: ~"baz" } ]; match x { - [first, ..tail] => { + [_, ..tail] => { match tail { [Foo { string: a }, Foo { string: b }] => { //~^ ERROR cannot move out of dereference of & pointer diff --git a/src/test/compile-fail/borrowck-vec-pattern-nesting.rs b/src/test/compile-fail/borrowck-vec-pattern-nesting.rs index 81f052918edd8..36ae5f8820892 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-nesting.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-nesting.rs @@ -17,4 +17,41 @@ fn b() { } } +fn c() { + let mut vec = [~1, ~2, ~3]; + match vec { + [_a, .._b] => { + //~^ ERROR cannot move out + + // Note: `_a` is *moved* here, but `b` is borrowing, + // hence illegal. + // + // See comment in middle/borrowck/gather_loans/mod.rs + // in the case covering these sorts of vectors. + } + _ => {} + } + let a = vec[0]; //~ ERROR use of partially moved value: `vec` +} + +fn d() { + let mut vec = [~1, ~2, ~3]; + match vec { + [.._a, _b] => { + //~^ ERROR cannot move out + } + _ => {} + } + let a = vec[0]; //~ ERROR use of partially moved value: `vec` +} + +fn e() { + let mut vec = [~1, ~2, ~3]; + match vec { + [_a, _b, _c] => {} + _ => {} + } + let a = vec[0]; //~ ERROR use of partially moved value: `vec` +} + fn main() {} diff --git a/src/test/run-pass/borrowck-newtype-issue-2573.rs b/src/test/run-pass/borrowck-newtype-issue-2573.rs deleted file mode 100644 index 5f0c7cad6191c..0000000000000 --- a/src/test/run-pass/borrowck-newtype-issue-2573.rs +++ /dev/null @@ -1,32 +0,0 @@ -// 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. - -struct foo {bar: baz} - -struct baz_ {baz: int} - -type baz = @mut baz_; - -trait frob { - fn frob(&self); -} - -impl frob for foo { - fn frob(&self) { - really_impure(self.bar); - } -} - -// Override default mode so that we are passing by value -fn really_impure(bar: baz) { - bar.baz = 3; -} - -pub fn main() {} diff --git a/src/test/run-pass/borrowck-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs b/src/test/run-pass/borrowck-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs index 056397f55ff26..c343258264748 100644 --- a/src/test/run-pass/borrowck-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs +++ b/src/test/run-pass/borrowck-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs @@ -28,14 +28,14 @@ fn main() { - let a = @mut [3i]; - let b = @mut [a]; - let c = @mut b; + let a = @mut 3i; + // let b = @mut [a]; + // let c = @mut [3]; // this should freeze `a` only - let _x: &mut [int] = c[0]; + let _x: &mut int = a; // hence these writes should not fail: - b[0] = b[0]; - c[0] = c[0]; + // b[0] = b[0]; + // c[0] = c[0]; } diff --git a/src/test/run-pass/match-pattern-drop.rs b/src/test/run-pass/match-pattern-drop.rs index 71bbb1768e892..3ce4ef8a94cd5 100644 --- a/src/test/run-pass/match-pattern-drop.rs +++ b/src/test/run-pass/match-pattern-drop.rs @@ -14,8 +14,11 @@ enum t { make_t(@int), clam, } fn foo(s: @int) { + debug!(::std::sys::refcount(s)); let count = ::std::sys::refcount(s); let x: t = make_t(s); // ref up + assert_eq!(::std::sys::refcount(s), count + 1u); + debug!(::std::sys::refcount(s)); match x { make_t(y) => { @@ -38,6 +41,5 @@ pub fn main() { debug!("%u", ::std::sys::refcount(s)); let count2 = ::std::sys::refcount(s); - let _ = ::std::sys::refcount(s); // don't get bitten by last-use. assert_eq!(count, count2); } diff --git a/src/test/run-pass/vec-tail-matching.rs b/src/test/run-pass/vec-tail-matching.rs index 6e1a47ad2dfd3..27f4fc833511a 100644 --- a/src/test/run-pass/vec-tail-matching.rs +++ b/src/test/run-pass/vec-tail-matching.rs @@ -9,7 +9,7 @@ pub fn main() { Foo { string: ~"baz" } ]; match x { - [first, ..tail] => { + [ref first, ..tail] => { assert!(first.string == ~"foo"); assert_eq!(tail.len(), 2); assert!(tail[0].string == ~"bar"); From 1670a8cfb13fd384d9fd4ca47034cef99118c7a7 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 20 Jun 2013 15:11:47 -0400 Subject: [PATCH 02/20] Add new tests for irrefutable patterns used in various tricky ways --- .../borrowck-move-in-irrefut-pat.rs | 16 ++++++++++++ .../borrowck-move-out-of-struct-with-dtor.rs | 22 ++++++++++++++++ ...owck-move-out-of-tuple-struct-with-dtor.rs | 22 ++++++++++++++++ .../compile-fail/regions-ref-in-fn-arg.rs | 11 ++++++++ .../run-pass/func-arg-incomplete-pattern.rs | 20 ++++++++++++++ src/test/run-pass/func-arg-ref-pattern.rs | 24 +++++++++++++++++ src/test/run-pass/func-arg-wild-pattern.rs | 10 +++++++ src/test/run-pass/let-destruct-ref.rs | 5 ++++ .../run-pass/match-drop-strs-issue-4541.rs | 26 +++++++++++++++++++ 9 files changed, 156 insertions(+) create mode 100644 src/test/compile-fail/borrowck-move-in-irrefut-pat.rs create mode 100644 src/test/compile-fail/borrowck-move-out-of-struct-with-dtor.rs create mode 100644 src/test/compile-fail/borrowck-move-out-of-tuple-struct-with-dtor.rs create mode 100644 src/test/compile-fail/regions-ref-in-fn-arg.rs create mode 100644 src/test/run-pass/func-arg-incomplete-pattern.rs create mode 100644 src/test/run-pass/func-arg-ref-pattern.rs create mode 100644 src/test/run-pass/func-arg-wild-pattern.rs create mode 100644 src/test/run-pass/let-destruct-ref.rs create mode 100644 src/test/run-pass/match-drop-strs-issue-4541.rs diff --git a/src/test/compile-fail/borrowck-move-in-irrefut-pat.rs b/src/test/compile-fail/borrowck-move-in-irrefut-pat.rs new file mode 100644 index 0000000000000..c99a1ee60d7fd --- /dev/null +++ b/src/test/compile-fail/borrowck-move-in-irrefut-pat.rs @@ -0,0 +1,16 @@ +fn with(f: &fn(&~str)) {} + +fn arg_item(&_x: &~str) {} + //~^ ERROR cannot move out of dereference of & pointer + +fn arg_closure() { + with(|&_x| ()) + //~^ ERROR cannot move out of dereference of & pointer +} + +fn let_pat() { + let &_x = &~"hi"; + //~^ ERROR cannot move out of dereference of & pointer +} + +pub fn main() {} \ No newline at end of file diff --git a/src/test/compile-fail/borrowck-move-out-of-struct-with-dtor.rs b/src/test/compile-fail/borrowck-move-out-of-struct-with-dtor.rs new file mode 100644 index 0000000000000..827e35e0c8302 --- /dev/null +++ b/src/test/compile-fail/borrowck-move-out-of-struct-with-dtor.rs @@ -0,0 +1,22 @@ +struct S {f:~str} +impl Drop for S { + fn finalize(&self) { println(self.f); } +} + +fn move_in_match() { + match S {f:~"foo"} { + S {f:_s} => {} + //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait + } +} + +fn move_in_let() { + let S {f:_s} = S {f:~"foo"}; + //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait +} + +fn move_in_fn_arg(S {f:_s}: S) { + //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait +} + +fn main() {} diff --git a/src/test/compile-fail/borrowck-move-out-of-tuple-struct-with-dtor.rs b/src/test/compile-fail/borrowck-move-out-of-tuple-struct-with-dtor.rs new file mode 100644 index 0000000000000..6013999d835d4 --- /dev/null +++ b/src/test/compile-fail/borrowck-move-out-of-tuple-struct-with-dtor.rs @@ -0,0 +1,22 @@ +struct S(~str); +impl Drop for S { + fn finalize(&self) { println(**self); } +} + +fn move_in_match() { + match S(~"foo") { + S(_s) => {} + //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait + } +} + +fn move_in_let() { + let S(_s) = S(~"foo"); + //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait +} + +fn move_in_fn_arg(S(_s): S) { + //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait +} + +fn main() {} diff --git a/src/test/compile-fail/regions-ref-in-fn-arg.rs b/src/test/compile-fail/regions-ref-in-fn-arg.rs new file mode 100644 index 0000000000000..f90fe924587df --- /dev/null +++ b/src/test/compile-fail/regions-ref-in-fn-arg.rs @@ -0,0 +1,11 @@ +fn arg_item(~ref x: ~int) -> &'static int { + x //~^ ERROR borrowed value does not live long enough +} + +fn with(f: &fn(~int) -> R) -> R { f(~3) } + +fn arg_closure() -> &'static int { + with(|~ref x| x) //~ ERROR borrowed value does not live long enough +} + +fn main() {} \ No newline at end of file diff --git a/src/test/run-pass/func-arg-incomplete-pattern.rs b/src/test/run-pass/func-arg-incomplete-pattern.rs new file mode 100644 index 0000000000000..b08d3beae1bfa --- /dev/null +++ b/src/test/run-pass/func-arg-incomplete-pattern.rs @@ -0,0 +1,20 @@ +// Test that we do not leak when the arg pattern must drop part of the +// argument (in this case, the `y` field). + +struct Foo { + x: ~uint, + y: ~uint, +} + +fn foo(Foo {x, _}: Foo) -> *uint { + let addr: *uint = &*x; + addr +} + +fn main() { + let obj = ~1; + let objptr: *uint = &*obj; + let f = Foo {x: obj, y: ~2}; + let xptr = foo(f); + assert_eq!(objptr, xptr); +} \ No newline at end of file diff --git a/src/test/run-pass/func-arg-ref-pattern.rs b/src/test/run-pass/func-arg-ref-pattern.rs new file mode 100644 index 0000000000000..84c2b3acf3580 --- /dev/null +++ b/src/test/run-pass/func-arg-ref-pattern.rs @@ -0,0 +1,24 @@ +// exec-env:RUST_POISON_ON_FREE=1 + +// Test argument patterns where we create refs to the inside of `~` +// boxes. Make sure that we don't free the box as we match the +// pattern. + +fn getaddr(~ref x: ~uint) -> *uint { + let addr: *uint = &*x; + addr +} + +fn checkval(~ref x: ~uint) -> uint { + *x +} + +fn main() { + let obj = ~1; + let objptr: *uint = &*obj; + let xptr = getaddr(obj); + assert_eq!(objptr, xptr); + + let obj = ~22; + assert_eq!(checkval(obj), 22); +} diff --git a/src/test/run-pass/func-arg-wild-pattern.rs b/src/test/run-pass/func-arg-wild-pattern.rs new file mode 100644 index 0000000000000..c2d60c8532993 --- /dev/null +++ b/src/test/run-pass/func-arg-wild-pattern.rs @@ -0,0 +1,10 @@ +// Test that we can compile code that uses a `_` in function argument +// patterns. + +fn foo((x, _): (int, int)) -> int { + x +} + +fn main() { + assert_eq!(foo((22, 23)), 22); +} diff --git a/src/test/run-pass/let-destruct-ref.rs b/src/test/run-pass/let-destruct-ref.rs new file mode 100644 index 0000000000000..7f3f9110b1c5c --- /dev/null +++ b/src/test/run-pass/let-destruct-ref.rs @@ -0,0 +1,5 @@ +fn main() { + let x = ~"hello"; + let ref y = x; + assert_eq!(x.slice(0, x.len()), y.slice(0, y.len())); +} diff --git a/src/test/run-pass/match-drop-strs-issue-4541.rs b/src/test/run-pass/match-drop-strs-issue-4541.rs new file mode 100644 index 0000000000000..ec65f36dc06f5 --- /dev/null +++ b/src/test/run-pass/match-drop-strs-issue-4541.rs @@ -0,0 +1,26 @@ +// Tests a tricky scenario involving string matching, +// copying, and moving to ensure that we don't segfault +// or double-free, as we were wont to do in the past. + +use std::io; + +fn parse_args() -> ~str { + let args = std::os::args(); + let mut n = 0; + + while n < args.len() { + match copy args[n] { + ~"-v" => (), + s => { + return s; + } + } + n += 1; + } + + return ~"" +} + +fn main() { + io::println(parse_args()); +} From ba13482dfabe4d0022f1fc2375b500cce53a05ce Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 20 Jun 2013 15:13:22 -0400 Subject: [PATCH 03/20] update ptr intrinsics and rewrite vec routines to be more correct. In particular, it is not valid to go around passing uninitialized or zero'd memory as arguments. Rust should generally be free to assume that the arguments it gets are valid input values, but the output of intrinsics::uninit() and intrinsics::init() are not (e.g., an @T is just null, leading to an error if we should try to increment the ref count). --- src/libstd/ptr.rs | 50 +++++++++++++++++ src/libstd/vec.rs | 134 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 144 insertions(+), 40 deletions(-) diff --git a/src/libstd/ptr.rs b/src/libstd/ptr.rs index aee6f1bd204e3..add2bbd7d44f4 100644 --- a/src/libstd/ptr.rs +++ b/src/libstd/ptr.rs @@ -142,6 +142,30 @@ pub unsafe fn set_memory(dst: *mut T, c: u8, count: uint) { memset64(dst, c, count as u64); } +/** + * Zeroes out `count` bytes of memory at `dst` + */ +#[inline] +#[cfg(not(stage0))] +pub unsafe fn zero_memory(dst: *mut T, count: uint) { + set_memory(dst, 0, count); +} + +/** + * Zeroes out `count * size_of::` bytes of memory at `dst` + */ +#[inline] +#[cfg(stage0)] +pub unsafe fn zero_memory(dst: *mut T, count: uint) { + let mut count = count * sys::size_of::(); + let mut dst = dst as *mut u8; + while count > 0 { + *dst = 0; + dst = mut_offset(dst, 1); + count -= 1; + } +} + /** * Swap the values at two mutable locations of the same type, without * deinitialising or copying either one. @@ -172,6 +196,32 @@ pub unsafe fn replace_ptr(dest: *mut T, mut src: T) -> T { src } +/** + * Reads the value from `*src` and returns it. Does not copy `*src`. + */ +#[inline(always)] +pub unsafe fn read_ptr(src: *mut T) -> T { + let mut tmp: T = intrinsics::uninit(); + let t: *mut T = &mut tmp; + copy_memory(t, src, 1); + tmp +} + +/** + * Reads the value from `*src` and nulls it out. + * This currently prevents destructors from executing. + */ +#[inline(always)] +pub unsafe fn read_and_zero_ptr(dest: *mut T) -> T { + // Copy the data out from `dest`: + let tmp = read_ptr(dest); + + // Now zero out `dest`: + zero_memory(dest, 1); + + tmp +} + /// Transform a region pointer - &T - to an unsafe pointer - *T. #[inline] pub fn to_unsafe_ptr(thing: &T) -> *T { diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 33857556548fa..cacb3156b75c5 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -1256,16 +1256,15 @@ impl OwnedVector for ~[T] { /// ~~~ #[inline] fn push_all_move(&mut self, mut rhs: ~[T]) { - let new_len = self.len() + rhs.len(); + let self_len = self.len(); + let rhs_len = rhs.len(); + let new_len = self_len + rhs_len; self.reserve(new_len); - unsafe { - do rhs.as_mut_buf |p, len| { - for uint::range(0, len) |i| { - let x = ptr::replace_ptr(ptr::mut_offset(p, i), - intrinsics::uninit()); - self.push(x); - } - } + unsafe { // Note: infallible. + let self_p = vec::raw::to_mut_ptr(*self); + let rhs_p = vec::raw::to_ptr(rhs); + ptr::copy_memory(ptr::mut_offset(self_p, self_len), rhs_p, rhs_len); + raw::set_len(self, new_len); raw::set_len(&mut rhs, 0); } } @@ -1277,9 +1276,8 @@ impl OwnedVector for ~[T] { ln => { let valptr = ptr::to_mut_unsafe_ptr(&mut self[ln - 1u]); unsafe { - let val = ptr::replace_ptr(valptr, intrinsics::init()); - raw::set_len(self, ln - 1u); - Some(val) + raw::set_len(v, ln - 1u); + ptr::read_ptr(valptr) } } } @@ -1410,7 +1408,7 @@ impl OwnedVector for ~[T] { unsafe { // This loop is optimized out for non-drop types. for uint::range(newlen, oldlen) |i| { - ptr::replace_ptr(ptr::mut_offset(p, i), intrinsics::uninit()); + ptr::read_and_zero_ptr(ptr::mut_offset(p, i)) } } } @@ -1555,37 +1553,93 @@ pub trait OwnedEqVector { impl OwnedEqVector for ~[T] { /** - * Remove consecutive repeated elements from a vector; if the vector is - * sorted, this removes all duplicates. - */ - pub fn dedup(&mut self) { + * Remove consecutive repeated elements from a vector; if the vector is + * sorted, this removes all duplicates. + */ + pub fn dedup(&mut self) { unsafe { - if self.len() == 0 { return; } - let mut last_written = 0; - let mut next_to_read = 1; - do self.as_mut_buf |p, ln| { - // last_written < next_to_read <= ln - while next_to_read < ln { - // last_written < next_to_read < ln - if *ptr::mut_offset(p, next_to_read) == - *ptr::mut_offset(p, last_written) { - ptr::replace_ptr(ptr::mut_offset(p, next_to_read), - intrinsics::uninit()); - } else { - last_written += 1; - // last_written <= next_to_read < ln - if next_to_read != last_written { - ptr::swap_ptr(ptr::mut_offset(p, last_written), - ptr::mut_offset(p, next_to_read)); - } + // Although we have a mutable reference to `self`, we cannot make + // *arbitrary* changes. There exists the possibility that this + // vector is contained with an `@mut` box and hence is still + // readable by the outside world during the `Eq` comparisons. + // Moreover, those comparisons could fail, so we must ensure + // that the vector is in a valid state at all time. + // + // The way that we handle this is by using swaps; we iterate + // over all the elements, swapping as we go so that at the end + // the elements we wish to keep are in the front, and those we + // wish to reject are at the back. We can then truncate the + // vector. This operation is still O(n). + // + // Example: We start in this state, where `r` represents "next + // read" and `w` represents "next_write`. + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], tis is not a duplicate, so + // we swap self[r] and self[w] (no effect as r==w) and then increment both + // r and w, leaving us with: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this value is a duplicate, + // so we increment `r` but leave everything else unchanged: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this is not a duplicate, + // so swap self[r] and self[w] and advance r and w: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 2 | 1 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Not a duplicate, repeat: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 2 | 3 | 1 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Duplicate, advance r. End of vec. Truncate to w. + + let ln = self.len(); + if ln < 1 { return; } + + // Avoid bounds checks by using unsafe pointers. + let p = vec::raw::to_mut_ptr(*self); + let mut r = 1; + let mut w = 1; + + while r < ln { + let p_r = ptr::mut_offset(p, r); + let p_wm1 = ptr::mut_offset(p, w - 1); + if *p_r != *p_wm1 { + if r != w { + let p_w = ptr::mut_offset(p_wm1, 1); + util::swap(&mut *p_r, &mut *p_w); } - // last_written <= next_to_read < ln - next_to_read += 1; - // last_written < next_to_read <= ln + w += 1; } + r += 1; } - // last_written < next_to_read == ln - raw::set_len(self, last_written + 1); + + self.truncate(w); } } } From 9999622e44558a6b138e7d5e3e98ba5db2eb1465 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 20 Jun 2013 15:14:30 -0400 Subject: [PATCH 04/20] Patch up some code that was using irrefutable patterns incorrectly. --- src/libstd/run.rs | 18 ++++++++++++------ src/libstd/vec.rs | 6 +++--- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/libstd/run.rs b/src/libstd/run.rs index 7e051b62171c8..b7bec95e6554e 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -715,10 +715,16 @@ fn with_envp(env: Option<&[(~str, ~str)]>, cb: &fn(*c_void) -> T) -> T { let mut tmps = ~[]; let mut ptrs = ~[]; - for es.iter().advance |&(k, v)| { - let kv = @fmt!("%s=%s", k, v); - tmps.push(kv); - ptrs.push(str::as_c_str(*kv, |b| b)); + for es.iter().advance |pair| { + // Use of match here is just to workaround limitations + // in the stage0 irrefutable pattern impl. + match pair { + &(ref k, ref v) => { + let kv = @fmt!("%s=%s", *k, *v); + tmps.push(kv); + ptrs.push(str::as_c_str(*kv, |b| b)); + } + } } ptrs.push(ptr::null()); @@ -1294,9 +1300,9 @@ mod tests { let output = str::from_bytes(prog.finish_with_output().output); let r = os::env(); - for r.iter().advance |&(k, v)| { + for r.iter().advance |&(ref k, ref v)| { // don't check windows magical empty-named variables - assert!(k.is_empty() || output.contains(fmt!("%s=%s", k, v))); + assert!(k.is_empty() || output.contains(fmt!("%s=%s", *k, *v))); } } #[test] diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index cacb3156b75c5..b4e891414f61c 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -281,16 +281,16 @@ pub trait VectorVector { impl<'self, T:Copy> VectorVector for &'self [~[T]] { /// Flattens a vector of slices of T into a single vector of T. pub fn concat_vec(&self) -> ~[T] { - self.flat_map(|&inner| inner) + self.flat_map(|inner| copy *inner) } /// Concatenate a vector of vectors, placing a given separator between each. pub fn connect_vec(&self, sep: &T) -> ~[T] { let mut r = ~[]; let mut first = true; - for self.iter().advance |&inner| { + for self.iter().advance |inner| { if first { first = false; } else { r.push(copy *sep); } - r.push_all(inner); + r.push_all(copy *inner); } r } From 366a233dbda597192b5ad027fe79f58331bc1bed Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 20 Jun 2013 15:15:03 -0400 Subject: [PATCH 05/20] syntax: Patch up code that was using irrefutable patterns incorrectly --- src/libsyntax/ext/deriving/generic.rs | 28 +++++++++++++++++---------- src/libsyntax/ext/pipes/proto.rs | 4 ++-- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs index 01769482d0829..d3554d6b27cd4 100644 --- a/src/libsyntax/ext/deriving/generic.rs +++ b/src/libsyntax/ext/deriving/generic.rs @@ -589,7 +589,7 @@ impl<'self> MethodDef<'self> { // transpose raw_fields let fields = match raw_fields { - [self_arg, .. rest] => { + [ref self_arg, .. rest] => { do self_arg.iter().enumerate().transform |(i, &(opt_id, field))| { let other_fields = do rest.map |l| { match &l[i] { @@ -738,16 +738,20 @@ impl<'self> MethodDef<'self> { let mut enum_matching_fields = vec::from_elem(self_vec.len(), ~[]); - for matches_so_far.tail().iter().advance |&(_, _, other_fields)| { - for other_fields.iter().enumerate().advance |(i, &(_, other_field))| { - enum_matching_fields[i].push(other_field); + for matches_so_far.tail().iter().advance |triple| { + match triple { + &(_, _, ref other_fields) => { + for other_fields.iter().enumerate().advance |(i, pair)| { + enum_matching_fields[i].push(pair.second()); + } + } } } let field_tuples = do self_vec.iter() .zip(enum_matching_fields.iter()) - .transform |(&(id, self_f), &other)| { - (id, self_f, other) + .transform |(&(id, self_f), other)| { + (id, self_f, copy *other) }.collect(); substructure = EnumMatching(variant_index, variant, field_tuples); } @@ -1015,7 +1019,8 @@ left-to-right (`true`) or right-to-left (`false`). pub fn cs_fold(use_foldl: bool, f: &fn(@ExtCtxt, span, old: @expr, - self_f: @expr, other_fs: &[@expr]) -> @expr, + self_f: @expr, + other_fs: &[@expr]) -> @expr, base: @expr, enum_nonmatch_f: EnumNonMatchFunc, cx: @ExtCtxt, span: span, @@ -1023,11 +1028,13 @@ pub fn cs_fold(use_foldl: bool, match *substructure.fields { EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => { if use_foldl { - do all_fields.iter().fold(base) |old, &(_, self_f, other_fs)| { + do all_fields.iter().fold(base) |old, triple| { + let (_, self_f, other_fs) = copy *triple; f(cx, span, old, self_f, other_fs) } } else { - do all_fields.rev_iter().fold(base) |old, &(_, self_f, other_fs)| { + do all_fields.rev_iter().fold(base) |old, triple| { + let (_, self_f, other_fs) = copy *triple; f(cx, span, old, self_f, other_fs) } } @@ -1059,7 +1066,8 @@ pub fn cs_same_method(f: &fn(@ExtCtxt, span, ~[@expr]) -> @expr, match *substructure.fields { EnumMatching(_, _, ref all_fields) | Struct(ref all_fields) => { // call self_n.method(other_1_n, other_2_n, ...) - let called = do all_fields.map |&(_, self_field, other_fields)| { + let called = do all_fields.map |triple| { + let (_, self_field, other_fields) = copy *triple; cx.expr_method_call(span, self_field, substructure.method_ident, diff --git a/src/libsyntax/ext/pipes/proto.rs b/src/libsyntax/ext/pipes/proto.rs index 2fe8456c2749c..75424b60390d7 100644 --- a/src/libsyntax/ext/pipes/proto.rs +++ b/src/libsyntax/ext/pipes/proto.rs @@ -215,8 +215,8 @@ pub fn visit>( // the copy keywords prevent recursive use of dvec let states: ~[Tstate] = do (copy proto.states).iter().transform |&s| { - let messages: ~[Tmessage] = do (copy s.messages).iter().transform |&m| { - let message(name, span, tys, this, next) = m; + let messages: ~[Tmessage] = do (copy s.messages).iter().transform |m| { + let message(name, span, tys, this, next) = copy *m; visitor.visit_message(name, span, tys, this, next) }.collect(); visitor.visit_state(s, messages) From 90843b6f58a042cd1548555064a80034a608c02b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 20 Jun 2013 15:15:16 -0400 Subject: [PATCH 06/20] extra: Patch up code that was using irrefutable patterns incorrectly. --- src/libextra/fileinput.rs | 15 ++++++++------- src/libextra/num/bigint.rs | 12 ++++++------ src/libextra/rc.rs | 2 +- src/libextra/terminfo/parm.rs | 4 ++-- src/libextra/treemap.rs | 10 +++++----- src/libextra/workcache.rs | 4 ++-- 6 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/libextra/fileinput.rs b/src/libextra/fileinput.rs index f91260f475288..de6edd540948d 100644 --- a/src/libextra/fileinput.rs +++ b/src/libextra/fileinput.rs @@ -419,7 +419,7 @@ mod test { let file = io::file_writer(path, [io::Create, io::Truncate]).get(); for contents.iter().advance |&str| { - file.write_str(str); + file.write_str(*str); file.write_char('\n'); } } @@ -445,7 +445,7 @@ mod test { |i| fmt!("tmp/lib-fileinput-test-fileinput-read-byte-%u.tmp", i)), true); // 3 files containing 0\n, 1\n, and 2\n respectively - for filenames.iter().enumerate().advance |(i, &filename)| { + for filenames.iter().enumerate().advance |(i, filename)| { make_file(filename.get_ref(), [fmt!("%u", i)]); } @@ -475,7 +475,7 @@ mod test { |i| fmt!("tmp/lib-fileinput-test-fileinput-read-%u.tmp", i)), true); // 3 files containing 1\n, 2\n, and 3\n respectively - for filenames.iter().enumerate().advance |(i, &filename)| { + for filenames.iter().enumerate().advance |(i, filename)| { make_file(filename.get_ref(), [fmt!("%u", i)]); } @@ -495,10 +495,11 @@ mod test { 3, |i| fmt!("tmp/lib-fileinput-test-input-vec-%u.tmp", i)), true); - for filenames.iter().enumerate().advance |(i, &filename)| { + for filenames.iter().enumerate().advance |(i, filename)| { let contents = vec::from_fn(3, |j| fmt!("%u %u", i, j)); make_file(filename.get_ref(), contents); + debug!("contents=%?", contents); all_lines.push_all(contents); } @@ -515,7 +516,7 @@ mod test { 3, |i| fmt!("tmp/lib-fileinput-test-input-vec-state-%u.tmp", i)),true); - for filenames.iter().enumerate().advance |(i, &filename)| { + for filenames.iter().enumerate().advance |(i, filename)| { let contents = vec::from_fn(3, |j| fmt!("%u %u", i, j + 1)); make_file(filename.get_ref(), contents); @@ -579,10 +580,10 @@ mod test { 3, |i| fmt!("tmp/lib-fileinput-test-next-file-%u.tmp", i)),true); - for filenames.iter().enumerate().advance |(i, &filename)| { + for filenames.iter().enumerate().advance |(i, filename)| { let contents = vec::from_fn(3, |j| fmt!("%u %u", i, j + 1)); - make_file(&filename.get(), contents); + make_file(filename.get_ref(), contents); } let in = FileInput::from_vec(filenames); diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs index a0b95924e09dc..918424748990a 100644 --- a/src/libextra/num/bigint.rs +++ b/src/libextra/num/bigint.rs @@ -1571,10 +1571,10 @@ mod biguint_tests { fn test_to_str_radix() { let r = to_str_pairs(); for r.iter().advance |num_pair| { - let &(n, rs) = num_pair; + let &(ref n, ref rs) = num_pair; for rs.iter().advance |str_pair| { - let &(radix, str) = str_pair; - assert_eq!(n.to_str_radix(radix), str); + let &(ref radix, ref str) = str_pair; + assert_eq!(&n.to_str_radix(*radix), str); } } } @@ -1583,10 +1583,10 @@ mod biguint_tests { fn test_from_str_radix() { let r = to_str_pairs(); for r.iter().advance |num_pair| { - let &(n, rs) = num_pair; + let &(ref n, ref rs) = num_pair; for rs.iter().advance |str_pair| { - let &(radix, str) = str_pair; - assert_eq!(&n, &FromStrRadix::from_str_radix(str, radix).get()); + let &(ref radix, ref str) = str_pair; + assert_eq!(&n, &FromStrRadix::from_str_radix(*str, *radix).get()); } } diff --git a/src/libextra/rc.rs b/src/libextra/rc.rs index 86080b343c78b..7cc8bca891077 100644 --- a/src/libextra/rc.rs +++ b/src/libextra/rc.rs @@ -73,7 +73,7 @@ impl Drop for Rc { if self.ptr.is_not_null() { (*self.ptr).count -= 1; if (*self.ptr).count == 0 { - ptr::replace_ptr(self.ptr, intrinsics::uninit()); + ptr::read_ptr(self.ptr); free(self.ptr as *c_void) } } diff --git a/src/libextra/terminfo/parm.rs b/src/libextra/terminfo/parm.rs index b7d21ea0ee3fd..f25d192cc0a9f 100644 --- a/src/libextra/terminfo/parm.rs +++ b/src/libextra/terminfo/parm.rs @@ -81,8 +81,8 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) // Copy parameters into a local vector for mutability let mut mparams = [Number(0), ..9]; - for mparams.mut_iter().zip(params.iter()).advance |(dst, &src)| { - *dst = src; + for mparams.mut_iter().zip(params.iter()).advance |(dst, src)| { + *dst = copy *src; } for cap.iter().transform(|&x| x).advance |c| { diff --git a/src/libextra/treemap.rs b/src/libextra/treemap.rs index a5f7479d41a01..f2dea8b9bbaf3 100644 --- a/src/libextra/treemap.rs +++ b/src/libextra/treemap.rs @@ -773,15 +773,15 @@ mod test_treemap { map: &TreeMap) { assert_eq!(ctrl.is_empty(), map.is_empty()); for ctrl.iter().advance |x| { - let &(k, v) = x; - assert!(map.find(&k).unwrap() == &v) + let &(ref k, ref v) = x; + assert!(map.find(k).unwrap() == v) } for map.iter().advance |(map_k, map_v)| { let mut found = false; for ctrl.iter().advance |x| { - let &(ctrl_k, ctrl_v) = x; - if *map_k == ctrl_k { - assert!(*map_v == ctrl_v); + let &(ref ctrl_k, ref ctrl_v) = x; + if *map_k == *ctrl_k { + assert!(*map_v == *ctrl_v); found = true; break; } diff --git a/src/libextra/workcache.rs b/src/libextra/workcache.rs index 503bd05b7337d..e7bec2fbd8d1c 100644 --- a/src/libextra/workcache.rs +++ b/src/libextra/workcache.rs @@ -157,8 +157,8 @@ impl Decodable for WorkMap { fn decode(d: &mut D) -> WorkMap { let v : ~[(WorkKey,~str)] = Decodable::decode(d); let mut w = WorkMap::new(); - for v.iter().advance |&(k, v)| { - w.insert(copy k, copy v); + for v.iter().advance |pair| { + w.insert(pair.first(), pair.second()); } w } From 41efcdf2996f842394277298a2f8045c432ba169 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 20 Jun 2013 15:21:37 -0400 Subject: [PATCH 07/20] Make all allocas named so we can see where they originate in the generated LLVM code. --- src/librustc/middle/trans/_match.rs | 16 ++++++++-------- src/librustc/middle/trans/base.rs | 21 +++++++++++---------- src/librustc/middle/trans/build.rs | 10 ++++++++-- src/librustc/middle/trans/cabi.rs | 4 ++-- src/librustc/middle/trans/callee.rs | 11 ++++++----- src/librustc/middle/trans/closure.rs | 2 +- src/librustc/middle/trans/common.rs | 4 ++++ src/librustc/middle/trans/datum.rs | 10 +++++----- src/librustc/middle/trans/expr.rs | 8 ++++---- src/librustc/middle/trans/foreign.rs | 7 ++++--- src/librustc/middle/trans/glue.rs | 2 +- src/librustc/middle/trans/reflect.rs | 2 +- src/librustc/middle/trans/tvec.rs | 4 ++-- src/librustc/middle/trans/write_guard.rs | 5 +++-- 14 files changed, 60 insertions(+), 46 deletions(-) diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index b7168cbfdec53..a58ee28404674 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -268,7 +268,7 @@ pub fn trans_opt(bcx: block, o: &Opt) -> opt_result { } lit(UnitLikeStructLit(pat_id)) => { let struct_ty = ty::node_id_to_type(bcx.tcx(), pat_id); - let datumblock = datum::scratch_datum(bcx, struct_ty, true); + let datumblock = datum::scratch_datum(bcx, struct_ty, "", true); return single_result(datumblock.to_result(bcx)); } lit(ConstLit(lit_id)) => { @@ -927,7 +927,7 @@ pub fn extract_vec_elems(bcx: block, ty::mt {ty: vt.unit_ty, mutbl: ast::m_imm}, ty::vstore_slice(ty::re_static) ); - let scratch = scratch_datum(bcx, slice_ty, false); + let scratch = scratch_datum(bcx, slice_ty, "", false); Store(bcx, slice_begin, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base]) ); @@ -1095,9 +1095,9 @@ pub fn compare_values(cx: block, match ty::get(rhs_t).sty { ty::ty_estr(ty::vstore_uniq) => { - let scratch_lhs = alloca(cx, val_ty(lhs)); + let scratch_lhs = alloca(cx, val_ty(lhs), "__lhs"); Store(cx, lhs, scratch_lhs); - let scratch_rhs = alloca(cx, val_ty(rhs)); + let scratch_rhs = alloca(cx, val_ty(rhs), "__rhs"); Store(cx, rhs, scratch_rhs); let did = cx.tcx().lang_items.uniq_str_eq_fn(); let result = callee::trans_lang_call(cx, did, [scratch_lhs, scratch_rhs], None); @@ -1636,12 +1636,12 @@ fn create_bindings_map(bcx: block, pat: @ast::pat) -> BindingsMap { // in this case, the final type of the variable will be T, // but during matching we need to store a *T as explained // above - let is_move = ccx.maps.moves_map.contains(&p_id); - llmatch = alloca(bcx, llvariable_ty.ptr_to()); - trmode = TrByValue(is_move, alloca(bcx, llvariable_ty)); + llmatch = alloca(bcx, llvariable_ty.ptr_to(), "__llmatch"); + trmode = TrByValue(alloca(bcx, llvariable_ty, + bcx.ident(ident))); } ast::bind_by_ref(_) => { - llmatch = alloca(bcx, llvariable_ty); + llmatch = alloca(bcx, llvariable_ty, bcx.ident(ident)); trmode = TrByRef; } }; diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 577f1c6896067..8da7c1351c7b8 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1012,7 +1012,7 @@ pub fn get_landing_pad(bcx: block) -> BasicBlockRef { match bcx.fcx.personality { Some(addr) => Store(pad_bcx, llretval, addr), None => { - let addr = alloca(pad_bcx, val_ty(llretval)); + let addr = alloca(pad_bcx, val_ty(llretval), ""); bcx.fcx.personality = Some(addr); Store(pad_bcx, llretval, addr); } @@ -1056,7 +1056,7 @@ pub fn do_spill(bcx: block, v: ValueRef, t: ty::t) -> ValueRef { if ty::type_is_bot(t) { return C_null(Type::i8p()); } - let llptr = alloc_ty(bcx, t); + let llptr = alloc_ty(bcx, t, ""); Store(bcx, v, llptr); return llptr; } @@ -1064,7 +1064,7 @@ pub fn do_spill(bcx: block, v: ValueRef, t: ty::t) -> ValueRef { // Since this function does *not* root, it is the caller's responsibility to // ensure that the referent is pointed to by a root. pub fn do_spill_noroot(cx: block, v: ValueRef) -> ValueRef { - let llptr = alloca(cx, val_ty(v)); + let llptr = alloca(cx, val_ty(v), ""); Store(cx, v, llptr); return llptr; } @@ -1561,20 +1561,20 @@ pub fn memzero(cx: block, llptr: ValueRef, ty: Type) { Call(cx, llintrinsicfn, [llptr, llzeroval, size, align, volatile]); } -pub fn alloc_ty(bcx: block, t: ty::t) -> ValueRef { +pub fn alloc_ty(bcx: block, t: ty::t, name: &str) -> ValueRef { let _icx = push_ctxt("alloc_ty"); let ccx = bcx.ccx(); let ty = type_of::type_of(ccx, t); assert!(!ty::type_has_params(t), "Type has params: %s", ty_to_str(ccx.tcx, t)); - let val = alloca(bcx, ty); + let val = alloca(bcx, ty, name); return val; } -pub fn alloca(cx: block, ty: Type) -> ValueRef { - alloca_maybe_zeroed(cx, ty, false) +pub fn alloca(cx: block, ty: Type, name: &str) -> ValueRef { + alloca_maybe_zeroed(cx, ty, name, false) } -pub fn alloca_maybe_zeroed(cx: block, ty: Type, zero: bool) -> ValueRef { +pub fn alloca_maybe_zeroed(cx: block, ty: Type, name: &str, zero: bool) -> ValueRef { let _icx = push_ctxt("alloca"); if cx.unreachable { unsafe { @@ -1582,7 +1582,7 @@ pub fn alloca_maybe_zeroed(cx: block, ty: Type, zero: bool) -> ValueRef { } } let initcx = base::raw_block(cx.fcx, false, cx.fcx.llstaticallocas); - let p = Alloca(initcx, ty); + let p = Alloca(initcx, ty, name); if zero { memzero(initcx, p, ty); } p } @@ -1623,7 +1623,8 @@ pub fn make_return_pointer(fcx: fn_ctxt, output_type: ty::t) -> ValueRef { llvm::LLVMGetParam(fcx.llfn, 0) } else { let lloutputtype = type_of::type_of(fcx.ccx, output_type); - alloca(raw_block(fcx, false, fcx.llstaticallocas), lloutputtype) + alloca(raw_block(fcx, false, fcx.llstaticallocas), lloutputtype, + "__make_return_pointer") } } } diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs index b62b73423e9b1..db5553ca939d7 100644 --- a/src/librustc/middle/trans/build.rs +++ b/src/librustc/middle/trans/build.rs @@ -505,11 +505,17 @@ pub fn ArrayMalloc(cx: block, Ty: Type, Val: ValueRef) -> ValueRef { } } -pub fn Alloca(cx: block, Ty: Type) -> ValueRef { +pub fn Alloca(cx: block, Ty: Type, name: &str) -> ValueRef { unsafe { if cx.unreachable { return llvm::LLVMGetUndef(Ty.ptr_to().to_ref()); } count_insn(cx, "alloca"); - return llvm::LLVMBuildAlloca(B(cx), Ty.to_ref(), noname()); + if name.is_empty() { + llvm::LLVMBuildAlloca(B(cx), Ty.to_ref(), noname()) + } else { + str::as_c_str( + name, + |c| llvm::LLVMBuildAlloca(B(cx), Ty.to_ref(), c)) + } } } diff --git a/src/librustc/middle/trans/cabi.rs b/src/librustc/middle/trans/cabi.rs index d00479194308b..8d741369e1a25 100644 --- a/src/librustc/middle/trans/cabi.rs +++ b/src/librustc/middle/trans/cabi.rs @@ -130,10 +130,10 @@ impl FnType { j = 1u; get_param(llwrapfn, 0u) } else if self.ret_ty.cast { - let retptr = alloca(bcx, self.ret_ty.ty); + let retptr = alloca(bcx, self.ret_ty.ty, ""); BitCast(bcx, retptr, ret_ty.ptr_to()) } else { - alloca(bcx, ret_ty) + alloca(bcx, ret_ty, "") }; let mut i = 0u; diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 473afda48e65d..cf81def3abf74 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -600,7 +600,7 @@ pub fn trans_call_inner(in_cx: block, let mut bcx = callee.bcx; let ccx = cx.ccx(); let ret_flag = if ret_in_loop { - let flag = alloca(bcx, Type::bool()); + let flag = alloca(bcx, Type::bool(), "__ret_flag"); Store(bcx, C_bool(false), flag); Some(flag) } else { @@ -675,7 +675,7 @@ pub fn trans_call_inner(in_cx: block, unsafe { if ty::type_needs_drop(bcx.tcx(), ret_ty) { if ty::type_is_immediate(bcx.tcx(), ret_ty) { - let llscratchptr = alloc_ty(bcx, ret_ty); + let llscratchptr = alloc_ty(bcx, ret_ty, "__ret"); Store(bcx, llresult, llscratchptr); bcx = glue::drop_ty(bcx, llscratchptr, ret_ty); } else { @@ -733,7 +733,7 @@ pub fn trans_ret_slot(bcx: block, fn_ty: ty::t, dest: Option) llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref()) } } else { - alloc_ty(bcx, retty) + alloc_ty(bcx, retty, "__trans_ret_slot") } } } @@ -823,7 +823,7 @@ pub fn trans_arg_expr(bcx: block, _ }) => { let scratch_ty = expr_ty(bcx, arg_expr); - let scratch = alloc_ty(bcx, scratch_ty); + let scratch = alloc_ty(bcx, scratch_ty, "__ret_flag"); let arg_ty = expr_ty(bcx, arg_expr); let sigil = ty::ty_closure_sigil(arg_ty); let bcx = closure::trans_expr_fn( @@ -895,7 +895,8 @@ pub fn trans_arg_expr(bcx: block, arg_datum.appropriate_mode(bcx.tcx()).is_by_ref() { debug!("by copy arg with type %s, storing to scratch", bcx.ty_to_str(arg_datum.ty)); - let scratch = scratch_datum(bcx, arg_datum.ty, false); + let scratch = scratch_datum(bcx, arg_datum.ty, + "__arg", false); arg_datum.store_to_datum(bcx, arg_expr.id, diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index 4c63b8dc84451..5b0212cc05cc7 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -193,7 +193,7 @@ pub fn allocate_cbox(bcx: block, sigil: ast::Sigil, cdata_ty: ty::t) } ast::BorrowedSigil => { let cbox_ty = tuplify_box_ty(tcx, cdata_ty); - let llbox = alloc_ty(bcx, cbox_ty); + let llbox = alloc_ty(bcx, cbox_ty, "__closure"); nuke_ref_count(bcx, llbox); rslt(bcx, llbox) } diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 973a124c48ad2..24648ada8935e 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -608,6 +608,10 @@ impl block_ { pub fn tcx(&self) -> ty::ctxt { self.fcx.ccx.tcx } pub fn sess(&self) -> Session { self.fcx.ccx.sess } + pub fn ident(&self, ident: ident) -> @str { + token::ident_to_str(&ident) + } + pub fn node_id_to_str(&self, id: ast::node_id) -> ~str { ast_map::node_id_to_str(self.tcx().items, id, self.sess().intr()) } diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index e86709d72b329..ed0adbcff873c 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -173,19 +173,19 @@ pub fn immediate_rvalue_bcx(bcx: block, return DatumBlock {bcx: bcx, datum: immediate_rvalue(val, ty)}; } -pub fn scratch_datum(bcx: block, ty: ty::t, zero: bool) -> Datum { +pub fn scratch_datum(bcx: block, ty: ty::t, name: &str, zero: bool) -> Datum { /*! - * * Allocates temporary space on the stack using alloca() and * returns a by-ref Datum pointing to it. If `zero` is true, the * space will be zeroed when it is allocated; this is normally not * necessary, but in the case of automatic rooting in match * statements it is possible to have temporaries that may not get * initialized if a certain arm is not taken, so we must zero - * them. You must arrange any cleanups etc yourself! */ + * them. You must arrange any cleanups etc yourself! + */ let llty = type_of::type_of(bcx.ccx(), ty); - let scratch = alloca_maybe_zeroed(bcx, llty, zero); + let scratch = alloca_maybe_zeroed(bcx, llty, name, zero); Datum { val: scratch, ty: ty, mode: ByRef(RevokeClean) } } @@ -476,7 +476,7 @@ impl Datum { if ty::type_is_nil(self.ty) || ty::type_is_bot(self.ty) { C_null(type_of::type_of(bcx.ccx(), self.ty).ptr_to()) } else { - let slot = alloc_ty(bcx, self.ty); + let slot = alloc_ty(bcx, self.ty, ""); Store(bcx, self.val, slot); slot } diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 0180eeb3d2205..2d5ac23b3b38b 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -274,7 +274,7 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { ty::mt { ty: unit_ty, mutbl: ast::m_imm }, ty::vstore_slice(ty::re_static)); - let scratch = scratch_datum(bcx, slice_ty, false); + let scratch = scratch_datum(bcx, slice_ty, "__adjust", false); Store(bcx, base, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base])); Store(bcx, len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len])); DatumBlock {bcx: bcx, datum: scratch} @@ -290,7 +290,7 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { let tcx = bcx.tcx(); let closure_ty = expr_ty_adjusted(bcx, expr); debug!("add_env(closure_ty=%s)", closure_ty.repr(tcx)); - let scratch = scratch_datum(bcx, closure_ty, false); + let scratch = scratch_datum(bcx, closure_ty, "__adjust", false); let llfn = GEPi(bcx, scratch.val, [0u, abi::fn_field_code]); assert_eq!(datum.appropriate_mode(tcx), ByValue); Store(bcx, datum.to_appropriate_llval(bcx), llfn); @@ -423,7 +423,7 @@ fn trans_to_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore); return nil(bcx, ty); } else { - let scratch = scratch_datum(bcx, ty, false); + let scratch = scratch_datum(bcx, ty, "", false); bcx = trans_rvalue_dps_unadjusted( bcx, expr, SaveIn(scratch.val)); @@ -1687,7 +1687,7 @@ fn trans_assign_op(bcx: block, // A user-defined operator method if bcx.ccx().maps.method_map.find(&expr.id).is_some() { // FIXME(#2528) evaluates the receiver twice!! - let scratch = scratch_datum(bcx, dst_datum.ty, false); + let scratch = scratch_datum(bcx, dst_datum.ty, "__assign_op", false); let bcx = trans_overloaded_op(bcx, expr, callee_id, diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 2c505853d5eb7..bdae222059894 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -195,14 +195,15 @@ fn build_wrap_fn_(ccx: @mut CrateContext, if needs_c_return && !ty::type_is_immediate(ccx.tcx, tys.fn_sig.output) { let lloutputtype = type_of::type_of(fcx.ccx, tys.fn_sig.output); fcx.llretptr = Some(alloca(raw_block(fcx, false, fcx.llstaticallocas), - lloutputtype)); + lloutputtype, + "")); } let bcx = top_scope_block(fcx, None); let lltop = bcx.llbb; // Allocate the struct and write the arguments into it. - let llargbundle = alloca(bcx, tys.bundle_ty); + let llargbundle = alloca(bcx, tys.bundle_ty, "__llargbundle"); arg_builder(bcx, tys, llwrapfn, llargbundle); // Create call itself. @@ -732,7 +733,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, let llsrcval = get_param(decl, first_real_arg); let llsrcptr = if ty::type_is_immediate(ccx.tcx, in_type) { - let llsrcptr = alloca(bcx, llintype); + let llsrcptr = alloca(bcx, llintype, "__llsrcptr"); Store(bcx, llsrcval, llsrcptr); llsrcptr } else { diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index bc493bfa23ec3..25e73fd640d43 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -132,7 +132,7 @@ pub fn free_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block { ty::ty_evec(_, ty::vstore_box) | ty::ty_estr(ty::vstore_box) | ty::ty_opaque_closure_ptr(_) => { - let vp = alloca(bcx, type_of(bcx.ccx(), t)); + let vp = alloca(bcx, type_of(bcx.ccx(), t), ""); Store(bcx, v, vp); free_ty(bcx, vp, t) } diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index cc4111aa1947d..a3b544dbc6195 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -57,7 +57,7 @@ impl Reflector { let bcx = self.bcx; let str_vstore = ty::vstore_slice(ty::re_static); let str_ty = ty::mk_estr(bcx.tcx(), str_vstore); - let scratch = scratch_datum(bcx, str_ty, false); + let scratch = scratch_datum(bcx, str_ty, "", false); let len = C_uint(bcx.ccx(), s.len() + 1); let c_str = PointerCast(bcx, C_cstr(bcx.ccx(), s), Type::i8p()); Store(bcx, c_str, GEPi(bcx, scratch.val, [ 0, 0 ])); diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index 41dbe320d2d10..825320b9ff636 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -332,7 +332,7 @@ pub fn trans_uniq_or_managed_vstore(bcx: block, heap: heap, vstore_expr: @ast::e let llptrval = PointerCast(bcx, llptrval, Type::i8p()); let llsizeval = C_uint(bcx.ccx(), s.len()); let typ = ty::mk_estr(bcx.tcx(), ty::vstore_uniq); - let lldestval = scratch_datum(bcx, typ, false); + let lldestval = scratch_datum(bcx, typ, "", false); let bcx = callee::trans_lang_call( bcx, bcx.tcx().lang_items.strdup_uniq_fn(), @@ -454,7 +454,7 @@ pub fn write_content(bcx: block, let loop_counter = { // i = 0 - let i = alloca(loop_bcx, bcx.ccx().int_type); + let i = alloca(loop_bcx, bcx.ccx().int_type, "__i"); Store(loop_bcx, C_uint(bcx.ccx(), 0), i); Br(loop_bcx, cond_bcx.llbb); diff --git a/src/librustc/middle/trans/write_guard.rs b/src/librustc/middle/trans/write_guard.rs index bd22e41aff8f0..1804a7334f23f 100644 --- a/src/librustc/middle/trans/write_guard.rs +++ b/src/librustc/middle/trans/write_guard.rs @@ -120,7 +120,7 @@ fn root(datum: &Datum, // First, root the datum. Note that we must zero this value, // because sometimes we root on one path but not another. // See e.g. #4904. - let scratch = scratch_datum(bcx, datum.ty, true); + let scratch = scratch_datum(bcx, datum.ty, "__write_guard", true); datum.copy_to_datum(bcx, INIT, scratch); let cleanup_bcx = find_bcx_for_scope(bcx, root_info.scope); add_clean_temp_mem_in_scope(cleanup_bcx, root_info.scope, scratch.val, scratch.ty); @@ -135,7 +135,8 @@ fn root(datum: &Datum, // scratch.val will be NULL should the cleanup get // called without the freezing actually occurring, and // return_to_mut checks for this condition. - let scratch_bits = scratch_datum(bcx, ty::mk_uint(), false); + let scratch_bits = scratch_datum(bcx, ty::mk_uint(), + "__write_guard_bits", false); let freeze_did = match freeze_kind { DynaImm => bcx.tcx().lang_items.borrow_as_imm_fn(), From 2d3262ca7b94b53178daa06fa72d5427584ae842 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 20 Jun 2013 15:23:52 -0400 Subject: [PATCH 08/20] Update trans to use type to decide when to move, not the moves table (simpler for cases where it's hard to decide what id to use for the lookup); modify irrefutable bindings code to move or copy depending on the type, rather than threading through a flag. Also updates how local variables and arguments are registered. These changes were hard to isolate. --- src/librustc/middle/astencode.rs | 11 +- src/librustc/middle/const_eval.rs | 1 - src/librustc/middle/trans/_match.rs | 312 ++++++++++++++++------- src/librustc/middle/trans/base.rs | 259 +++++++++---------- src/librustc/middle/trans/callee.rs | 2 - src/librustc/middle/trans/controlflow.rs | 3 - src/librustc/middle/trans/datum.rs | 16 +- src/librustc/middle/trans/expr.rs | 58 +++-- 8 files changed, 387 insertions(+), 275 deletions(-) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 72b6f8e1c805b..7412eba115631 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -53,7 +53,6 @@ pub struct Maps { method_map: middle::typeck::method_map, vtable_map: middle::typeck::vtable_map, write_guard_map: middle::borrowck::write_guard_map, - moves_map: middle::moves::MovesMap, capture_map: middle::moves::CaptureMap, } @@ -952,12 +951,6 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, } } - if maps.moves_map.contains(&id) { - do ebml_w.tag(c::tag_table_moves_map) |ebml_w| { - ebml_w.id(id); - } - } - { let r = maps.capture_map.find(&id); for r.iter().advance |&cap_vars| { @@ -1121,9 +1114,7 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext, xcx.dcx.tcx.sess.bug( fmt!("unknown tag found in side tables: %x", tag)); } - Some(value) => if value == c::tag_table_moves_map { - dcx.maps.moves_map.insert(id); - } else { + Some(value) => { let val_doc = entry_doc.get(c::tag_table_val as uint); let mut val_dsr = reader::Decoder(val_doc); let val_dsr = &mut val_dsr; diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index bf91b6771dcd8..af39dea6d79e1 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -187,7 +187,6 @@ pub fn lookup_const_by_id(tcx: ty::ctxt, method_map: @mut HashMap::new(), vtable_map: @mut HashMap::new(), write_guard_map: @mut HashSet::new(), - moves_map: @mut HashSet::new(), capture_map: @mut HashMap::new() }; match csearch::maybe_get_item_ast(tcx, def_id, diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index a58ee28404674..a9a3c9317b44f 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -316,7 +316,7 @@ pub fn variant_opt(bcx: block, pat_id: ast::node_id) } pub enum TransBindingMode { - TrByValue(/*ismove:*/ bool, /*llbinding:*/ ValueRef), + TrByValue(/*llbinding:*/ ValueRef), TrByRef, } @@ -1138,18 +1138,11 @@ fn store_non_ref_bindings(bcx: block, let mut bcx = bcx; for bindings_map.each_value |&binding_info| { match binding_info.trmode { - TrByValue(is_move, lldest) => { + TrByValue(lldest) => { let llval = Load(bcx, binding_info.llmatch); // get a T* let datum = Datum {val: llval, ty: binding_info.ty, mode: ByRef(ZeroMem)}; - bcx = { - if is_move { - datum.move_to(bcx, INIT, lldest) - } else { - datum.copy_to(bcx, INIT, lldest) - } - }; - + bcx = datum.store_to(bcx, INIT, lldest); do opt_temp_cleanups.mutate |temp_cleanups| { add_clean_temp_mem(bcx, lldest, binding_info.ty); temp_cleanups.push(lldest); @@ -1181,7 +1174,7 @@ fn insert_lllocals(bcx: block, let llval = match binding_info.trmode { // By value bindings: use the stack slot that we // copied/moved the value into - TrByValue(_, lldest) => { + TrByValue(lldest) => { if add_cleans { add_clean(bcx, lldest, binding_info.ty); } @@ -1245,7 +1238,7 @@ pub fn compile_guard(bcx: block, let mut bcx = bcx; for data.bindings_map.each_value |&binding_info| { match binding_info.trmode { - TrByValue(_, llval) => { + TrByValue(llval) => { bcx = glue::drop_ty(bcx, llval, binding_info.ty); } TrByRef => {} @@ -1737,53 +1730,204 @@ pub enum IrrefutablePatternBindingMode { BindArgument } -// Not match-related, but similar to the pattern-munging code above -pub fn bind_irrefutable_pat(bcx: block, - pat: @ast::pat, - val: ValueRef, - make_copy: bool, - binding_mode: IrrefutablePatternBindingMode) - -> block { - let _icx = push_ctxt("match::bind_irrefutable_pat"); - let ccx = bcx.fcx.ccx; +pub fn store_local(bcx: block, + pat: @ast::pat, + opt_init_expr: Option<@ast::expr>) + -> block { + /*! + * Generates code for a local variable declaration like + * `let ;` or `let = `. + */ let mut bcx = bcx; - // Necessary since bind_irrefutable_pat is called outside trans_match - match pat.node { - ast::pat_ident(_, _, ref inner) => { - if pat_is_variant_or_struct(bcx.tcx().def_map, pat) { - return bcx; + return match opt_init_expr { + Some(init_expr) => { + // Optimize the "let x = expr" case. This just writes + // the result of evaluating `expr` directly into the alloca + // for `x`. Often the general path results in similar or the + // same code post-optimization, but not always. In particular, + // in unsafe code, you can have expressions like + // + // let x = intrinsics::uninit(); + // + // In such cases, the more general path is unsafe, because + // it assumes it is matching against a valid value. + match simple_identifier(pat) { + Some(path) => { + return mk_binding_alloca( + bcx, pat.id, path, BindLocal, + |bcx, _, llval| expr::trans_into(bcx, init_expr, + expr::SaveIn(llval))); + } + + None => {} } - if make_copy { - let binding_ty = node_id_type(bcx, pat.id); - let datum = Datum {val: val, ty: binding_ty, - mode: ByRef(RevokeClean)}; - let scratch = scratch_datum(bcx, binding_ty, false); - datum.copy_to_datum(bcx, INIT, scratch); - match binding_mode { - BindLocal => { - bcx.fcx.lllocals.insert(pat.id, scratch.val); - } - BindArgument => { - bcx.fcx.llargs.insert(pat.id, scratch.val); - } - } - add_clean(bcx, scratch.val, binding_ty); + // General path. + let init_datum = + unpack_datum!( + bcx, + expr::trans_to_datum(bcx, init_expr)); + if ty::type_is_bot(expr_ty(bcx, init_expr)) { + create_dummy_locals(bcx, pat) } else { - match binding_mode { - BindLocal => { - bcx.fcx.lllocals.insert(pat.id, val); - } - BindArgument => { - bcx.fcx.llargs.insert(pat.id, val); - } + if bcx.sess().asm_comments() { + add_comment(bcx, "creating zeroable ref llval"); } + let llptr = init_datum.to_zeroable_ref_llval(bcx); + return bind_irrefutable_pat(bcx, pat, llptr, BindLocal); } + } + None => { + create_dummy_locals(bcx, pat) + } + }; - for inner.iter().advance |inner_pat| { - bcx = bind_irrefutable_pat( - bcx, *inner_pat, val, true, binding_mode); + fn create_dummy_locals(mut bcx: block, pat: @ast::pat) -> block { + // create dummy memory for the variables if we have no + // value to store into them immediately + let tcx = bcx.tcx(); + do pat_bindings(tcx.def_map, pat) |_, p_id, _, path| { + bcx = mk_binding_alloca( + bcx, p_id, path, BindLocal, + |bcx, var_ty, llval| { zero_mem(bcx, llval, var_ty); bcx }); + } + bcx + } +} + +pub fn store_arg(mut bcx: block, + pat: @ast::pat, + llval: ValueRef) + -> block { + /*! + * Generates code for argument patterns like `fn foo(: T)`. + * Creates entries in the `llargs` map for each of the bindings + * in `pat`. + * + * # Arguments + * + * - `pat` is the argument pattern + * - `llval` is a pointer to the argument value (in other words, + * if the argument type is `T`, then `llval` is a `T*`). In some + * cases, this code may zero out the memory `llval` points at. + */ + + // We always need to cleanup the argument as we exit the fn scope. + // Note that we cannot do it before for fear of a fn like + // fn getaddr(~ref x: ~uint) -> *uint {....} + // (From test `run-pass/func-arg-ref-pattern.rs`) + let arg_ty = node_id_type(bcx, pat.id); + add_clean(bcx, llval, arg_ty); + + match simple_identifier(pat) { + Some(_) => { + // Optimized path for `x: T` case. This just adopts + // `llval` wholesale as the pointer for `x`, avoiding the + // general logic which may copy out of `llval`. + bcx.fcx.llargs.insert(pat.id, llval); + } + + None => { + // General path. Copy out the values that are used in the + // pattern. + bcx = bind_irrefutable_pat(bcx, pat, llval, BindArgument); + } + } + + return bcx; +} + +fn mk_binding_alloca(mut bcx: block, + p_id: ast::node_id, + path: @ast::Path, + binding_mode: IrrefutablePatternBindingMode, + populate: &fn(block, ty::t, ValueRef) -> block) -> block { + let var_ty = node_id_type(bcx, p_id); + let ident = ast_util::path_to_ident(path); + let llval = alloc_ty(bcx, var_ty, bcx.ident(ident)); + bcx = populate(bcx, var_ty, llval); + let llmap = match binding_mode { + BindLocal => bcx.fcx.lllocals, + BindArgument => bcx.fcx.llargs + }; + llmap.insert(p_id, llval); + add_clean(bcx, llval, var_ty); + return bcx; +} + +fn bind_irrefutable_pat(bcx: block, + pat: @ast::pat, + val: ValueRef, + binding_mode: IrrefutablePatternBindingMode) + -> block { + /*! + * A simple version of the pattern matching code that only handles + * irrefutable patterns. This is used in let/argument patterns, + * not in match statements. Unifying this code with the code above + * sounds nice, but in practice it produces very inefficient code, + * since the match code is so much more general. In most cases, + * LLVM is able to optimize the code, but it causes longer compile + * times and makes the generated code nigh impossible to read. + * + * # Arguments + * - bcx: starting basic block context + * - pat: the irrefutable pattern being matched. + * - val: a pointer to the value being matched. If pat matches a value + * of type T, then this is a T*. If the value is moved from `pat`, + * then `*pat` will be zeroed; otherwise, it's existing cleanup + * applies. + * - binding_mode: is this for an argument or a local variable? + */ + + debug!("bind_irrefutable_pat(bcx=%s, pat=%s, val=%s, binding_mode=%?)", + bcx.to_str(), + pat_to_str(pat, bcx.sess().intr()), + val_str(bcx.ccx().tn, val), + binding_mode); + + if bcx.sess().asm_comments() { + add_comment(bcx, fmt!("bind_irrefutable_pat(pat=%s)", + pat_to_str(pat, bcx.sess().intr()))); + } + + let _indenter = indenter(); + + let _icx = bcx.insn_ctxt("alt::bind_irrefutable_pat"); + let mut bcx = bcx; + let tcx = bcx.tcx(); + let ccx = bcx.ccx(); + match pat.node { + ast::pat_ident(pat_binding_mode, path, inner) => { + if pat_is_binding(tcx.def_map, pat) { + // Allocate the stack slot where the value of this + // binding will live and place it into the appropriate + // map. + bcx = mk_binding_alloca( + bcx, pat.id, path, binding_mode, + |bcx, variable_ty, llvariable_val| { + match pat_binding_mode { + ast::bind_infer => { + // By value binding: move the value that `val` + // points at into the binding's stack slot. + let datum = Datum {val: val, + ty: variable_ty, + mode: ByRef(ZeroMem)}; + datum.store_to(bcx, INIT, llvariable_val) + } + + ast::bind_by_ref(_) => { + // By ref binding: the value of the variable + // is the pointer `val` itself. + Store(bcx, val, llvariable_val); + bcx + } + } + }); + } + + for inner.iter().advance |&inner_pat| { + bcx = bind_irrefutable_pat(bcx, inner_pat, val, binding_mode); } } ast::pat_enum(_, ref sub_pats) => { @@ -1799,11 +1943,8 @@ pub fn bind_irrefutable_pat(bcx: block, val); for sub_pats.iter().advance |sub_pat| { for args.vals.iter().enumerate().advance |(i, argval)| { - bcx = bind_irrefutable_pat(bcx, - sub_pat[i], - *argval, - make_copy, - binding_mode); + bcx = bind_irrefutable_pat(bcx, sub_pat[i], + *argval, binding_mode); } } } @@ -1818,19 +1959,14 @@ pub fn bind_irrefutable_pat(bcx: block, let repr = adt::represent_node(bcx, pat.id); for elems.iter().enumerate().advance |(i, elem)| { let fldptr = adt::trans_field_ptr(bcx, repr, - val, 0, i); - bcx = bind_irrefutable_pat(bcx, - *elem, - fldptr, - make_copy, - binding_mode); + val, 0, i); + bcx = bind_irrefutable_pat(bcx, *elem, + fldptr, binding_mode); } } } } Some(&ast::def_static(_, false)) => { - bcx = bind_irrefutable_pat(bcx, pat, val, make_copy, - binding_mode); } _ => { // Nothing to do here. @@ -1845,12 +1981,8 @@ pub fn bind_irrefutable_pat(bcx: block, for fields.iter().advance |f| { let ix = ty::field_idx_strict(tcx, f.ident, field_tys); let fldptr = adt::trans_field_ptr(bcx, pat_repr, val, - discr, ix); - bcx = bind_irrefutable_pat(bcx, - f.pat, - fldptr, - make_copy, - binding_mode); + discr, ix); + bcx = bind_irrefutable_pat(bcx, f.pat, fldptr, binding_mode); } } } @@ -1858,11 +1990,7 @@ pub fn bind_irrefutable_pat(bcx: block, let repr = adt::represent_node(bcx, pat.id); for elems.iter().enumerate().advance |(i, elem)| { let fldptr = adt::trans_field_ptr(bcx, repr, val, 0, i); - bcx = bind_irrefutable_pat(bcx, - *elem, - fldptr, - make_copy, - binding_mode); + bcx = bind_irrefutable_pat(bcx, *elem, fldptr, binding_mode); } } ast::pat_box(inner) | ast::pat_uniq(inner) => { @@ -1872,22 +2000,30 @@ pub fn bind_irrefutable_pat(bcx: block, ty::ty_uniq(*) if !ty::type_contents(bcx.tcx(), pat_ty).contains_managed() => llbox, _ => GEPi(bcx, llbox, [0u, abi::box_field_body]) }; - bcx = bind_irrefutable_pat(bcx, - inner, - unboxed, - true, - binding_mode); + bcx = bind_irrefutable_pat(bcx, inner, unboxed, binding_mode); } ast::pat_region(inner) => { let loaded_val = Load(bcx, val); - bcx = bind_irrefutable_pat(bcx, - inner, - loaded_val, - true, - binding_mode); - } - ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) | - ast::pat_vec(*) => () + bcx = bind_irrefutable_pat(bcx, inner, loaded_val, binding_mode); + } + ast::pat_vec(*) => { + bcx.tcx().sess.span_bug( + pat.span, + fmt!("vector patterns are never irrefutable!")); + } + ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) => () } return bcx; } + +fn simple_identifier(pat: @ast::pat) -> Option<@ast::Path> { + match pat.node { + ast::pat_ident(ast::bind_infer, path, None) => { + Some(path) + } + _ => { + None + } + } +} + diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 8da7c1351c7b8..75d9f89a8d7d5 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -59,6 +59,7 @@ use middle::trans::type_of::*; use middle::ty; use util::common::indenter; use util::ppaux::{Repr, ty_to_str}; +use middle::pat_util; use middle::trans::type_::Type; @@ -75,7 +76,7 @@ use extra::time; use extra::sort; use syntax::ast::ident; use syntax::ast_map::{path, path_elt_to_str, path_name}; -use syntax::ast_util::{local_def, path_to_ident}; +use syntax::ast_util::{local_def}; use syntax::attr; use syntax::codemap::span; use syntax::parse::token; @@ -1121,9 +1122,6 @@ pub fn init_local(bcx: block, local: &ast::local) -> block { let _indenter = indenter(); let _icx = push_ctxt("init_local"); - let ty = node_id_type(bcx, local.node.id); - - debug!("ty=%s", bcx.ty_to_str(ty)); if ignore_lhs(bcx, local) { // Handle let _ = e; just like e; @@ -1135,36 +1133,7 @@ pub fn init_local(bcx: block, local: &ast::local) -> block { } } - let llptr = match bcx.fcx.lllocals.find_copy(&local.node.id) { - Some(v) => v, - _ => { - bcx.tcx().sess.span_bug(local.span, - "init_local: Someone forgot to document why it's\ - safe to assume local.node.init must be local_mem!"); - } - }; - - let mut bcx = bcx; - match local.node.init { - Some(init) => { - bcx = expr::trans_into(bcx, init, expr::SaveIn(llptr)); - } - _ => { - zero_mem(bcx, llptr, ty); - } - } - - // Make a note to drop this slot on the way out. - debug!("adding clean for %?/%s to bcx=%s", - local.node.id, bcx.ty_to_str(ty), - bcx.to_str()); - add_clean(bcx, llptr, ty); - - return _match::bind_irrefutable_pat(bcx, - local.node.pat, - llptr, - false, - _match::BindLocal); + _match::store_local(bcx, local.node.pat, local.node.init) } pub fn trans_stmt(cx: block, s: &ast::stmt) -> block { @@ -1469,6 +1438,7 @@ pub fn block_locals(b: &ast::blk, it: &fn(@ast::local)) { } } +<<<<<<< variant A pub fn alloc_local(cx: block, local: &ast::local) -> block { let _icx = push_ctxt("alloc_local"); let t = node_id_type(cx, local.node.id); @@ -1491,6 +1461,31 @@ pub fn alloc_local(cx: block, local: &ast::local) -> block { } +>>>>>>> variant B +####### Ancestor +pub fn alloc_local(cx: block, local: @ast::local) -> block { + let _icx = push_ctxt("alloc_local"); + let t = node_id_type(cx, local.node.id); + let simple_name = match local.node.pat.node { + ast::pat_ident(_, pth, None) => Some(path_to_ident(pth)), + _ => None + }; + let val = alloc_ty(cx, t); + if cx.sess().opts.debuginfo { + for simple_name.iter().advance |name| { + str::as_c_str(cx.ccx().sess.str_of(*name), |buf| { + unsafe { + llvm::LLVMSetValueName(val, buf) + } + }); + } + } + cx.fcx.lllocals.insert(local.node.id, val); + cx +} + + +======= end pub fn with_cond(bcx: block, val: ValueRef, f: &fn(block) -> block) -> block { let _icx = push_ctxt("with_cond"); let next_cx = base::sub_block(bcx, "next"); @@ -1739,6 +1734,7 @@ pub fn create_llargs_for_fn_args(cx: fn_ctxt, let arg = &args[i]; let llarg = llvm::LLVMGetParam(cx.llfn, arg_n as c_uint); + // FIXME #7260: aliasing should be determined by monomorphized ty::t match arg.ty.node { // `~` pointers never alias other parameters, because ownership was transferred ast::ty_uniq(_) => { @@ -1783,7 +1779,6 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt, for uint::range(0, arg_tys.len()) |arg_n| { let arg_ty = arg_tys[arg_n]; let raw_llarg = raw_llargs[arg_n]; - let arg_id = args[arg_n].id; // For certain mode/type combinations, the raw llarg values are passed // by value. However, within the fn body itself, we want to always @@ -1794,22 +1789,13 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt, // the event it's not truly needed. // only by value if immediate: let llarg = if datum::appropriate_mode(bcx.tcx(), arg_ty).is_by_value() { - let alloc = alloc_ty(bcx, arg_ty); + let alloc = alloc_ty(bcx, arg_ty, "__arg"); Store(bcx, raw_llarg, alloc); alloc } else { raw_llarg }; - - add_clean(bcx, llarg, arg_ty); - - bcx = _match::bind_irrefutable_pat(bcx, - args[arg_n].pat, - llarg, - false, - _match::BindArgument); - - fcx.llargs.insert(arg_id, llarg); + bcx = _match::store_arg(bcx, args[arg_n].pat, llarg); if fcx.ccx.sess.opts.extra_debuginfo && fcx_has_nonzero_span(fcx) { debuginfo::create_arg(bcx, &args[arg_n], args[arg_n].ty.span); @@ -1968,81 +1954,51 @@ pub fn trans_fn(ccx: @mut CrateContext, |_bcx| { }); } +fn insert_synthetic_type_entries(bcx: block, + fn_args: &[ast::arg], + arg_tys: &[ty::t]) +{ + /*! + * For tuple-like structs and enum-variants, we generate + * synthetic AST nodes for the arguments. These have no types + * in the type table and no entries in the moves table, + * so the code in `copy_args_to_allocas` and `bind_irrefutable_pat` + * gets upset. This hack of a function bridges the gap by inserting types. + * + * This feels horrible. I think we should just have a special path + * for these functions and not try to use the generic code, but + * that's not the problem I'm trying to solve right now. - nmatsakis + */ + + let tcx = bcx.tcx(); + for uint::range(0, fn_args.len()) |i| { + debug!("setting type of argument %u (pat node %d) to %s", + i, fn_args[i].pat.id, bcx.ty_to_str(arg_tys[i])); + + let pat_id = fn_args[i].pat.id; + let arg_ty = arg_tys[i]; + tcx.node_types.insert(pat_id as uint, arg_ty); + } +} + pub fn trans_enum_variant(ccx: @mut CrateContext, - enum_id: ast::node_id, + _enum_id: ast::node_id, variant: &ast::variant, args: &[ast::variant_arg], disr: int, param_substs: Option<@param_substs>, llfndecl: ValueRef) { let _icx = push_ctxt("trans_enum_variant"); - // Translate variant arguments to function arguments. - let fn_args = do args.map |varg| { - ast::arg { - is_mutbl: false, - ty: copy varg.ty, - pat: ast_util::ident_to_pat( - ccx.tcx.sess.next_node_id(), - codemap::dummy_sp(), - special_idents::arg), - id: varg.id, - } - }; - let ty_param_substs = match param_substs { - Some(ref substs) => { copy substs.tys } - None => ~[] - }; - let enum_ty = ty::subst_tps(ccx.tcx, - ty_param_substs, - None, - ty::node_id_to_type(ccx.tcx, enum_id)); - let fcx = new_fn_ctxt_w_id(ccx, - ~[], - llfndecl, - variant.node.id, - enum_ty, - param_substs, - None); - - let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args); - let bcx = top_scope_block(fcx, None); - let lltop = bcx.llbb; - let arg_tys = ty::ty_fn_args(node_id_type(bcx, variant.node.id)); - let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys); - - // XXX is there a better way to reconstruct the ty::t? - let repr = adt::represent_type(ccx, enum_ty); - - debug!("trans_enum_variant: name=%s tps=%s repr=%? enum_ty=%s", - unsafe { str::raw::from_c_str(llvm::LLVMGetValueName(llfndecl)) }, - ~"[" + ty_param_substs.map(|&t| ty_to_str(ccx.tcx, t)).connect(", ") + "]", - repr, ty_to_str(ccx.tcx, enum_ty)); - - adt::trans_start_init(bcx, repr, fcx.llretptr.get(), disr); - for args.iter().enumerate().advance |(i, va)| { - let lldestptr = adt::trans_field_ptr(bcx, - repr, - fcx.llretptr.get(), - disr, - i); - - // If this argument to this function is a enum, it'll have come in to - // this function as an opaque blob due to the way that type_of() - // works. So we have to cast to the destination's view of the type. - let llarg = match fcx.llargs.find(&va.id) { - Some(&x) => x, - _ => fail!("trans_enum_variant: how do we know this works?"), - }; - let arg_ty = arg_tys[i]; - memcpy_ty(bcx, lldestptr, llarg, arg_ty); - } - build_return(bcx); - finish_fn(fcx, lltop); + trans_enum_variant_or_tuple_like_struct( + ccx, + variant.node.id, + args, + disr, + param_substs, + llfndecl); } -// NB: In theory this should be merged with the function above. But the AST -// structures are completely different, so very little code would be shared. pub fn trans_tuple_struct(ccx: @mut CrateContext, fields: &[@ast::struct_field], ctor_id: ast::node_id, @@ -2050,37 +2006,72 @@ pub fn trans_tuple_struct(ccx: @mut CrateContext, llfndecl: ValueRef) { let _icx = push_ctxt("trans_tuple_struct"); - // Translate struct fields to function arguments. - let fn_args = do fields.map |field| { + trans_enum_variant_or_tuple_like_struct( + ccx, + ctor_id, + fields, + 0, + param_substs, + llfndecl); +} + +trait IdAndTy { + fn id(&self) -> ast::node_id; + fn ty(&self) -> @ast::Ty; +} + +impl IdAndTy for ast::variant_arg { + fn id(&self) -> ast::node_id { self.id } + fn ty(&self) -> @ast::Ty { self.ty } +} + +impl IdAndTy for @ast::struct_field { + fn id(&self) -> ast::node_id { self.node.id } + fn ty(&self) -> @ast::Ty { self.node.ty } +} + +pub fn trans_enum_variant_or_tuple_like_struct( + ccx: @mut CrateContext, + ctor_id: ast::node_id, + args: &[A], + disr: int, + param_substs: Option<@param_substs>, + llfndecl: ValueRef) +{ + // Translate variant arguments to function arguments. + let fn_args = do args.map |varg| { ast::arg { is_mutbl: false, - ty: copy field.node.ty, - pat: ast_util::ident_to_pat(ccx.tcx.sess.next_node_id(), - codemap::dummy_sp(), - special_idents::arg), - id: field.node.id + ty: varg.ty(), + pat: ast_util::ident_to_pat( + ccx.tcx.sess.next_node_id(), + codemap::dummy_sp(), + special_idents::arg), + id: varg.id(), } }; - // XXX is there a better way to reconstruct the ty::t? let ty_param_substs = match param_substs { Some(ref substs) => { copy substs.tys } None => ~[] }; + let ctor_ty = ty::subst_tps(ccx.tcx, ty_param_substs, None, ty::node_id_to_type(ccx.tcx, ctor_id)); - let tup_ty = match ty::get(ctor_ty).sty { + + let result_ty = match ty::get(ctor_ty).sty { ty::ty_bare_fn(ref bft) => bft.sig.output, - _ => ccx.sess.bug(fmt!("trans_tuple_struct: unexpected ctor \ - return type %s", - ty_to_str(ccx.tcx, ctor_ty))) + _ => ccx.sess.bug( + fmt!("trans_enum_variant_or_tuple_like_struct: \ + unexpected ctor return type %s", + ty_to_str(ccx.tcx, ctor_ty))) }; let fcx = new_fn_ctxt_w_id(ccx, ~[], llfndecl, ctor_id, - tup_ty, + result_ty, param_substs, None); @@ -2088,23 +2079,23 @@ pub fn trans_tuple_struct(ccx: @mut CrateContext, let bcx = top_scope_block(fcx, None); let lltop = bcx.llbb; - let arg_tys = ty::ty_fn_args(node_id_type(bcx, ctor_id)); - let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys); + let arg_tys = ty::ty_fn_args(ctor_ty); - let repr = adt::represent_type(ccx, tup_ty); - adt::trans_start_init(bcx, repr, fcx.llretptr.get(), 0); + insert_synthetic_type_entries(bcx, fn_args, arg_tys); + let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys); - for fields.iter().enumerate().advance |(i, field)| { + let repr = adt::represent_type(ccx, result_ty); + adt::trans_start_init(bcx, repr, fcx.llretptr.get(), disr); + for fn_args.iter().enumerate().advance |(i, fn_arg)| { let lldestptr = adt::trans_field_ptr(bcx, repr, fcx.llretptr.get(), - 0, + disr, i); - let llarg = fcx.llargs.get_copy(&field.node.id); + let llarg = fcx.llargs.get_copy(&fn_arg.pat.id); let arg_ty = arg_tys[i]; memcpy_ty(bcx, lldestptr, llarg, arg_ty); } - build_return(bcx); finish_fn(fcx, lltop); } @@ -3039,8 +3030,8 @@ pub fn trans_crate(sess: session::Session, } } if ccx.sess.count_llvm_insns() { - for ccx.stats.llvm_insns.iter().advance |(&k, &v)| { - io::println(fmt!("%-7u %s", v, k)); + for ccx.stats.llvm_insns.each |k, v| { + io::println(fmt!("%-7u %s", *v, *k)); } } diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index cf81def3abf74..216338e111787 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -860,8 +860,6 @@ pub fn trans_arg_expr(bcx: block, // FIXME(#3548) use the adjustments table match autoref_arg { DoAutorefArg => { - assert!(! - bcx.ccx().maps.moves_map.contains(&arg_expr.id)); val = arg_datum.to_ref_llval(bcx); } DontAutorefArg => { diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index 8ca4253ead8b8..904e6e14e28db 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -35,9 +35,6 @@ use syntax::codemap::span; pub fn trans_block(bcx: block, b: &ast::blk, dest: expr::Dest) -> block { let _icx = push_ctxt("trans_block"); let mut bcx = bcx; - do block_locals(b) |local| { - bcx = alloc_local(bcx, local); - }; for b.node.stmts.iter().advance |s| { debuginfo::update_source_pos(bcx, b.span); bcx = trans_stmt(bcx, *s); diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index ed0adbcff873c..1de619433afbd 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -70,8 +70,8 @@ * This is a "shallow" clone. After `move_to()`, the current datum * is invalid and should no longer be used. * - * - `store_to()` either performs a copy or a move by consulting the - * moves_map computed by `middle::moves`. + * - `store_to()` either performs a copy or a move depending on the + * Rust type of the datum. * * # Scratch datum * @@ -208,7 +208,6 @@ pub fn appropriate_mode(tcx: ty::ctxt, ty: ty::t) -> DatumMode { impl Datum { pub fn store_to(&self, bcx: block, - id: ast::node_id, action: CopyAction, dst: ValueRef) -> block { @@ -218,7 +217,7 @@ impl Datum { * `id` is located in the move table, but copies otherwise. */ - if bcx.ccx().maps.moves_map.contains(&id) { + if ty::type_moves_by_default(bcx.tcx(), self.ty) { self.move_to(bcx, action, dst) } else { self.copy_to(bcx, action, dst) @@ -227,7 +226,6 @@ impl Datum { pub fn store_to_dest(&self, bcx: block, - id: ast::node_id, dest: expr::Dest) -> block { match dest { @@ -235,21 +233,20 @@ impl Datum { return bcx; } expr::SaveIn(addr) => { - return self.store_to(bcx, id, INIT, addr); + return self.store_to(bcx, INIT, addr); } } } pub fn store_to_datum(&self, bcx: block, - id: ast::node_id, action: CopyAction, datum: Datum) -> block { debug!("store_to_datum(self=%s, action=%?, datum=%s)", self.to_str(bcx.ccx()), action, datum.to_str(bcx.ccx())); assert!(datum.mode.is_by_ref()); - self.store_to(bcx, id, action, datum.val) + self.store_to(bcx, action, datum.val) } pub fn move_to_datum(&self, bcx: block, action: CopyAction, datum: Datum) @@ -828,11 +825,10 @@ impl DatumBlock { } pub fn store_to(&self, - id: ast::node_id, action: CopyAction, dst: ValueRef) -> block { - self.datum.store_to(self.bcx, id, action, dst) + self.datum.store_to(self.bcx, action, dst) } pub fn copy_to(&self, action: CopyAction, dst: ValueRef) -> block { diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 2d5ac23b3b38b..19a0f7262ff6e 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -23,7 +23,8 @@ This will generate code that evaluates `expr`, storing the result into `Dest`, which must either be the special flag ignore (throw the result away) or be a pointer to memory of the same type/size as the expression. It returns the resulting basic block. This form will -handle all automatic adjustments and moves for you. +handle all automatic adjustments for you. The value will be moved if +its type is linear and copied otherwise. ## Translation to a datum @@ -42,18 +43,18 @@ This function generates code to evaluate the expression and return a tries to return its result in the most efficient way possible, without introducing extra copies or sacrificing information. Therefore, for lvalue expressions, you always get a by-ref `Datum` in return that -points at the memory for this lvalue (almost, see [1]). For rvalue -expressions, we will return a by-value `Datum` whenever possible, but -it is often necessary to allocate a stack slot, store the result of -the rvalue in there, and then return a pointer to the slot (see the -discussion later on about the different kinds of rvalues). +points at the memory for this lvalue. For rvalue expressions, we will +return a by-value `Datum` whenever possible, but it is often necessary +to allocate a stack slot, store the result of the rvalue in there, and +then return a pointer to the slot (see the discussion later on about +the different kinds of rvalues). NB: The `trans_to_datum()` function does perform adjustments, but since it returns a pointer to the value "in place" it does not handle -any moves that may be relevant. If you are transing an expression -whose result should be moved, you should either use the Datum methods -`move_to()` (for unconditional moves) or `store_to()` (for moves -conditioned on the type of the expression) at some point. +moves. If you wish to copy/move the value returned into a new +location, you should use the Datum method `store_to()` (move or copy +depending on type). You can also use `move_to()` (force move) or +`copy_to()` (force copy) for special situations. ## Translating local variables @@ -110,13 +111,6 @@ generate phi nodes). Finally, statement rvalues are rvalues that always produce a nil return type, such as `while` loops or assignments (`a = b`). -## Caveats - -[1] Actually, some lvalues are only stored by value and not by -reference. An example (as of this writing) would be immutable -arguments or pattern bindings of immediate type. However, mutable -lvalues are *never* stored by value. - */ @@ -315,7 +309,7 @@ pub fn trans_into(bcx: block, expr: @ast::expr, dest: Dest) -> block { let datumblock = trans_to_datum(bcx, expr); return match dest { Ignore => datumblock.bcx, - SaveIn(lldest) => datumblock.store_to(expr.id, INIT, lldest) + SaveIn(lldest) => datumblock.store_to(INIT, lldest) }; } @@ -343,7 +337,7 @@ pub fn trans_into(bcx: block, expr: @ast::expr, dest: Dest) -> block { let datumblock = trans_lvalue_unadjusted(bcx, expr); match dest { Ignore => datumblock.bcx, - SaveIn(lldest) => datumblock.store_to(expr.id, INIT, lldest) + SaveIn(lldest) => datumblock.store_to(INIT, lldest) } } ty::RvalueDatumExpr => { @@ -351,8 +345,9 @@ pub fn trans_into(bcx: block, expr: @ast::expr, dest: Dest) -> block { match dest { Ignore => datumblock.drop_val(), - // NB: We always do `move_to()` regardless of the - // moves_map because we're processing an rvalue + // When processing an rvalue, the value will be newly + // allocated, so we always `move_to` so as not to + // unnecessarily inc ref counts and so forth: SaveIn(lldest) => datumblock.move_to(INIT, lldest) } } @@ -386,11 +381,11 @@ fn trans_lvalue(bcx: block, expr: @ast::expr) -> DatumBlock { fn trans_to_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { /*! - * * Translates an expression into a datum. If this expression * is an rvalue, this will result in a temporary value being - * created. If you already know where the result should be stored, - * you should use `trans_into()` instead. */ + * created. If you plan to store the value somewhere else, + * you should prefer `trans_into()` instead. + */ let mut bcx = bcx; @@ -535,7 +530,7 @@ fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block { let dst_datum = unpack_datum!( bcx, trans_lvalue(bcx, dst)); return src_datum.store_to_datum( - bcx, src.id, DROP_EXISTING, dst_datum); + bcx, DROP_EXISTING, dst_datum); } ast::expr_assign_op(callee_id, op, dst, src) => { return trans_assign_op(bcx, expr, callee_id, op, dst, src); @@ -638,7 +633,15 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, return trans_into(bcx, blk, dest); } ast::expr_copy(a) => { - return trans_into(bcx, a, dest); + // If we just called `trans_into(bcx, a, dest)`, then this + // might *move* the value into `dest` if the value is + // non-copyable. So first get a datum and then do an + // explicit copy. + let datumblk = trans_to_datum(bcx, a); + return match dest { + Ignore => datumblk.bcx, + SaveIn(llval) => datumblk.copy_to(INIT, llval) + }; } ast::expr_call(f, ref args, _) => { return callee::trans_call( @@ -1221,6 +1224,7 @@ fn trans_adt(bcx: block, repr: &adt::Repr, discr: int, bcx = trans_into(bcx, e, Ignore); } for optbase.iter().advance |sbi| { + // FIXME #7261: this moves entire base, not just certain fields bcx = trans_into(bcx, sbi.expr, Ignore); } return bcx; @@ -1245,7 +1249,7 @@ fn trans_adt(bcx: block, repr: &adt::Repr, discr: int, adt::trans_field_ptr(bcx, repr, srcval, discr, i) }; let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i); - bcx = datum.store_to(bcx, base.expr.id, INIT, dest); + bcx = datum.store_to(bcx, INIT, dest); } } From 729b07f83c9f6319f68482ce781521ac666cf6e6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 20 Jun 2013 15:25:52 -0400 Subject: [PATCH 09/20] Modify borrow checker to visit irrefutable patterns that appear in let and function arguments; modify type checker to store type information for all patterns and handles some missing cases. --- src/librustc/middle/borrowck/check_loans.rs | 91 ++++++------ .../middle/borrowck/gather_loans/lifetime.rs | 10 +- .../middle/borrowck/gather_loans/mod.rs | 129 +++++++++++++----- .../borrowck/gather_loans/restrictions.rs | 2 +- src/librustc/middle/borrowck/mod.rs | 6 +- src/librustc/middle/borrowck/move_data.rs | 18 +++ src/librustc/middle/check_match.rs | 22 +-- src/librustc/middle/dataflow.rs | 2 +- src/librustc/middle/mem_categorization.rs | 49 ++++--- src/librustc/middle/moves.rs | 46 ++++++- src/librustc/middle/typeck/check/_match.rs | 20 +-- src/librustc/middle/typeck/check/writeback.rs | 5 +- 12 files changed, 249 insertions(+), 151 deletions(-) diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index b2e303d40eecf..a455bdc436cad 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -65,7 +65,7 @@ pub fn check_loans(bccx: @BorrowckCtxt, enum MoveError { MoveOk, - MoveWhileBorrowed(/*move*/@LoanPath, /*loan*/@LoanPath, /*loan*/span) + MoveWhileBorrowed(/*loan*/@LoanPath, /*loan*/span) } impl<'self> CheckLoanCtxt<'self> { @@ -348,7 +348,7 @@ impl<'self> CheckLoanCtxt<'self> { cmt = b; } - mc::cat_rvalue | + mc::cat_rvalue(*) | mc::cat_static_item | mc::cat_implicit_self | mc::cat_copied_upvar(*) | @@ -547,45 +547,50 @@ impl<'self> CheckLoanCtxt<'self> { self.bccx.loan_path_to_str(loan_path))); } - pub fn check_move_out_from_expr(&self, ex: @ast::expr) { - match ex.node { - ast::expr_paren(*) => { - /* In the case of an expr_paren(), the expression inside - * the parens will also be marked as being moved. Ignore - * the parents then so as not to report duplicate errors. */ + fn check_move_out_from_expr(&self, expr: @ast::expr) { + match expr.node { + ast::expr_fn_block(*) => { + // moves due to capture clauses are checked + // in `check_loans_in_fn`, so that we can + // give a better error message } _ => { - let cmt = self.bccx.cat_expr(ex); - match self.analyze_move_out_from_cmt(cmt) { - MoveOk => {} - MoveWhileBorrowed(move_path, loan_path, loan_span) => { - self.bccx.span_err( - cmt.span, - fmt!("cannot move out of `%s` \ - because it is borrowed", - self.bccx.loan_path_to_str(move_path))); - self.bccx.span_note( - loan_span, - fmt!("borrow of `%s` occurs here", - self.bccx.loan_path_to_str(loan_path))); - } + self.check_move_out_from_id(expr.id, expr.span) + } + } + } + + fn check_move_out_from_id(&self, id: ast::node_id, span: span) { + for self.move_data.each_path_moved_by(id) |_, move_path| { + match self.analyze_move_out_from(id, move_path) { + MoveOk => {} + MoveWhileBorrowed(loan_path, loan_span) => { + self.bccx.span_err( + span, + fmt!("cannot move out of `%s` \ + because it is borrowed", + self.bccx.loan_path_to_str(move_path))); + self.bccx.span_note( + loan_span, + fmt!("borrow of `%s` occurs here", + self.bccx.loan_path_to_str(loan_path))); } } } } - pub fn analyze_move_out_from_cmt(&self, cmt: mc::cmt) -> MoveError { - debug!("analyze_move_out_from_cmt(cmt=%s)", cmt.repr(self.tcx())); + pub fn analyze_move_out_from(&self, + expr_id: ast::node_id, + move_path: @LoanPath) -> MoveError { + debug!("analyze_move_out_from(expr_id=%?, move_path=%s)", + expr_id, move_path.repr(self.tcx())); // FIXME(#4384) inadequare if/when we permit `move a.b` // check for a conflicting loan: - let r = opt_loan_path(cmt); - for r.iter().advance |&lp| { - for self.each_in_scope_restriction(cmt.id, lp) |loan, _| { - // Any restriction prevents moves. - return MoveWhileBorrowed(lp, loan.loan_path, loan.span); - } + for self.each_in_scope_restriction(expr_id, move_path) |loan, _| { + // Any restriction prevents moves. + return MoveWhileBorrowed(loan.loan_path, loan.span); } MoveOk @@ -652,13 +657,11 @@ fn check_loans_in_fn<'a>(fk: &visit::fn_kind, closure_id: ast::node_id, cap_var: &moves::CaptureVar) { let var_id = ast_util::def_id_of_def(cap_var.def).node; - let ty = ty::node_id_to_type(this.tcx(), var_id); - let cmt = this.bccx.cat_def(closure_id, cap_var.span, - ty, cap_var.def); - let move_err = this.analyze_move_out_from_cmt(cmt); + let move_path = @LpVar(var_id); + let move_err = this.analyze_move_out_from(closure_id, move_path); match move_err { MoveOk => {} - MoveWhileBorrowed(move_path, loan_path, loan_span) => { + MoveWhileBorrowed(loan_path, loan_span) => { this.bccx.span_err( cap_var.span, fmt!("cannot move `%s` into closure \ @@ -689,10 +692,7 @@ fn check_loans_in_expr<'a>(expr: @ast::expr, expr.repr(this.tcx())); this.check_for_conflicting_loans(expr.id); - - if this.bccx.moves_map.contains(&expr.id) { - this.check_move_out_from_expr(expr); - } + this.check_move_out_from_expr(expr); match expr.node { ast::expr_self | @@ -742,18 +742,7 @@ fn check_loans_in_pat<'a>(pat: @ast::pat, visit::vt<@mut CheckLoanCtxt<'a>>)) { this.check_for_conflicting_loans(pat.id); - - // Note: moves out of pattern bindings are not checked by - // the borrow checker, at least not directly. What happens - // is that if there are any moved bindings, the discriminant - // will be considered a move, and this will be checked as - // normal. Then, in `middle::check_match`, we will check - // that no move occurs in a binding that is underneath an - // `@` or `&`. Together these give the same guarantees as - // `check_move_out_from_expr()` without requiring us to - // rewalk the patterns and rebuild the pattern - // categorizations. - + this.check_move_out_from_id(pat.id, pat.span); visit::visit_pat(pat, (this, vt)); } diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs index 05fc139305c4a..5d91916d0044a 100644 --- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -67,7 +67,7 @@ impl GuaranteeLifetimeContext { //! Main routine. Walks down `cmt` until we find the "guarantor". match cmt.cat { - mc::cat_rvalue | + mc::cat_rvalue(*) | mc::cat_implicit_self | mc::cat_copied_upvar(*) | // L-Local mc::cat_local(*) | // L-Local @@ -179,7 +179,7 @@ impl GuaranteeLifetimeContext { //! lvalue. cmt.mutbl.is_immutable() || match cmt.guarantor().cat { - mc::cat_rvalue => true, + mc::cat_rvalue(*) => true, _ => false } } @@ -299,7 +299,7 @@ impl GuaranteeLifetimeContext { mc::cat_arg(id) => { self.bccx.moved_variables_set.contains(&id) } - mc::cat_rvalue | + mc::cat_rvalue(*) | mc::cat_static_item | mc::cat_implicit_self | mc::cat_copied_upvar(*) | @@ -325,8 +325,8 @@ impl GuaranteeLifetimeContext { // See the SCOPE(LV) function in doc.rs match cmt.cat { - mc::cat_rvalue => { - ty::re_scope(self.bccx.tcx.region_maps.cleanup_scope(cmt.id)) + mc::cat_rvalue(cleanup_scope_id) => { + ty::re_scope(cleanup_scope_id) } mc::cat_implicit_self | mc::cat_copied_upvar(_) => { diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index 26fa4924ccb52..86baf53528427 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -73,6 +73,7 @@ struct GatherLoanCtxt { } pub fn gather_loans(bccx: @BorrowckCtxt, + decl: &ast::fn_decl, body: &ast::blk) -> (id_range, @mut ~[Loan], @mut move_data::MoveData) { let glcx = @mut GatherLoanCtxt { @@ -83,6 +84,7 @@ pub fn gather_loans(bccx: @BorrowckCtxt, repeating_ids: ~[body.node.id], move_data: @mut MoveData::new() }; + glcx.gather_fn_arg_patterns(decl, body); let v = visit::mk_vt(@visit::Visitor {visit_expr: gather_loans_in_expr, visit_block: gather_loans_in_block, visit_fn: gather_loans_in_fn, @@ -124,6 +126,7 @@ fn gather_loans_in_fn(fk: &visit::fn_kind, this.push_repeating_id(body.node.id); visit::visit_fn(fk, decl, body, sp, id, (this, v)); this.pop_repeating_id(body.node.id); + this.gather_fn_arg_patterns(decl, body); } } } @@ -138,26 +141,33 @@ fn gather_loans_in_block(blk: &ast::blk, fn gather_loans_in_local(local: @ast::local, (this, vt): (@mut GatherLoanCtxt, visit::vt<@mut GatherLoanCtxt>)) { - if local.node.init.is_none() { - // Variable declarations without initializers are considered "moves": - let tcx = this.bccx.tcx; - do pat_util::pat_bindings(tcx.def_map, local.node.pat) |_, id, span, _| { - gather_moves::gather_decl(this.bccx, - this.move_data, - id, - span, - id); + match local.node.init { + None => { + // Variable declarations without initializers are considered "moves": + let tcx = this.bccx.tcx; + do pat_util::pat_bindings(tcx.def_map, local.node.pat) + |_, id, span, _| { + gather_moves::gather_decl(this.bccx, + this.move_data, + id, + span, + id); + } } - } else { - // Variable declarations with initializers are considered "assigns": - let tcx = this.bccx.tcx; - do pat_util::pat_bindings(tcx.def_map, local.node.pat) |_, id, span, _| { - gather_moves::gather_assignment(this.bccx, - this.move_data, - id, - span, - @LpVar(id), - id); + Some(init) => { + // Variable declarations with initializers are considered "assigns": + let tcx = this.bccx.tcx; + do pat_util::pat_bindings(tcx.def_map, local.node.pat) + |_, id, span, _| { + gather_moves::gather_assignment(this.bccx, + this.move_data, + id, + span, + @LpVar(id), + id); + } + let init_cmt = this.bccx.cat_expr(init); + this.gather_pat(init_cmt, local.node.pat, None); } } @@ -230,7 +240,7 @@ fn gather_loans_in_expr(ex: @ast::expr, let cmt = this.bccx.cat_expr(ex_v); for arms.iter().advance |arm| { for arm.pats.iter().advance |pat| { - this.gather_pat(cmt, *pat, arm.body.node.id, ex.id); + this.gather_pat(cmt, *pat, Some((arm.body.node.id, ex.id))); } } visit::visit_expr(ex, (this, vt)); @@ -596,11 +606,40 @@ impl GatherLoanCtxt { } } - pub fn gather_pat(&mut self, - discr_cmt: mc::cmt, - root_pat: @ast::pat, - arm_body_id: ast::node_id, - match_id: ast::node_id) { + fn gather_fn_arg_patterns(&mut self, + decl: &ast::fn_decl, + body: &ast::blk) { + /*! + * Walks the patterns for fn arguments, checking that they + * do not attempt illegal moves or create refs that outlive + * the arguments themselves. Just a shallow wrapper around + * `gather_pat()`. + */ + + let mc_ctxt = self.bccx.mc_ctxt(); + for decl.inputs.each |arg| { + let arg_ty = ty::node_id_to_type(self.tcx(), arg.pat.id); + + let arg_cmt = mc_ctxt.cat_rvalue( + arg.id, + arg.pat.span, + body.node.id, // Arguments live only as long as the fn body. + arg_ty); + + self.gather_pat(arg_cmt, arg.pat, None); + } + } + + fn gather_pat(&mut self, + discr_cmt: mc::cmt, + root_pat: @ast::pat, + arm_match_ids: Option<(ast::node_id, ast::node_id)>) { + /*! + * Walks patterns, examining the bindings to determine if they + * cause borrows (`ref` bindings, vector patterns) or + * moves (non-`ref` bindings with linear type). + */ + do self.bccx.cat_pattern(discr_cmt, root_pat) |cmt, pat| { match pat.node { ast::pat_ident(bm, _, _) if self.pat_is_binding(pat) => { @@ -621,15 +660,19 @@ impl GatherLoanCtxt { // with a cat_discr() node. There is a detailed // discussion of the function of this node in // `lifetime.rs`: - let arm_scope = ty::re_scope(arm_body_id); - if self.bccx.is_subregion_of(scope_r, arm_scope) { - let cmt_discr = self.bccx.cat_discr(cmt, match_id); - self.guarantee_valid(pat.id, pat.span, - cmt_discr, mutbl, scope_r); - } else { - self.guarantee_valid(pat.id, pat.span, - cmt, mutbl, scope_r); - } + let cmt_discr = match arm_match_ids { + None => cmt, + Some((arm_id, match_id)) => { + let arm_scope = ty::re_scope(arm_id); + if self.bccx.is_subregion_of(scope_r, arm_scope) { + self.bccx.cat_discr(cmt, match_id) + } else { + cmt + } + } + }; + self.guarantee_valid(pat.id, pat.span, + cmt_discr, mutbl, scope_r); } ast::bind_infer => { // No borrows here, but there may be moves @@ -652,6 +695,24 @@ impl GatherLoanCtxt { self.vec_slice_info(slice_pat, slice_ty); let mcx = self.bccx.mc_ctxt(); let cmt_index = mcx.cat_index(slice_pat, cmt, 0); + + // Note: We declare here that the borrow occurs upon + // entering the `[...]` pattern. This implies that + // something like `[a, ..b]` where `a` is a move is + // illegal, because the borrow is already in effect. + // In fact such a move would be safe-ish, but it + // effectively *requires* that we use the nulling + // out semantics to indicate when a value has been + // moved, which we are trying to move away from. + // Otherwise, how can we indicate that the first + // element in the vector has been moved? + // Eventually, we could perhaps modify this rule to + // permit `[..a, b]` where `b` is a move, because in + // that case we can adjust the length of the + // original vec accordingly, but we'd have to make + // trans do the right thing, and it would only work + // for `~` vectors. It seems simpler to just require + // that people call `vec.pop()` or `vec.unshift()`. self.guarantee_valid(pat.id, pat.span, cmt_index, slice_mutbl, slice_r); } diff --git a/src/librustc/middle/borrowck/gather_loans/restrictions.rs b/src/librustc/middle/borrowck/gather_loans/restrictions.rs index d5377aeb61839..e568da5eedfae 100644 --- a/src/librustc/middle/borrowck/gather_loans/restrictions.rs +++ b/src/librustc/middle/borrowck/gather_loans/restrictions.rs @@ -64,7 +64,7 @@ impl RestrictionsContext { } match cmt.cat { - mc::cat_rvalue => { + mc::cat_rvalue(*) => { // Effectively, rvalues are stored into a // non-aliasable temporary on the stack. Since they // are inherently non-aliasable, they can only be diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 2e3813f57e081..47d35d73df09b 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -124,7 +124,7 @@ fn borrowck_fn(fk: &visit::fn_kind, // Check the body of fn items. let (id_range, all_loans, move_data) = - gather_loans::gather_loans(this, body); + gather_loans::gather_loans(this, decl, body); let mut loan_dfcx = DataFlowContext::new(this.tcx, this.method_map, @@ -264,7 +264,7 @@ pub fn opt_loan_path(cmt: mc::cmt) -> Option<@LoanPath> { //! traverses the CMT. match cmt.cat { - mc::cat_rvalue | + mc::cat_rvalue(*) | mc::cat_static_item | mc::cat_copied_upvar(_) | mc::cat_implicit_self => { @@ -485,7 +485,7 @@ impl BorrowckCtxt { pub fn mc_ctxt(&self) -> mc::mem_categorization_ctxt { mc::mem_categorization_ctxt {tcx: self.tcx, - method_map: self.method_map} + method_map: self.method_map} } pub fn cat_pattern(&self, diff --git a/src/librustc/middle/borrowck/move_data.rs b/src/librustc/middle/borrowck/move_data.rs index 73adade7a5d71..7ec1ff3c628e4 100644 --- a/src/librustc/middle/borrowck/move_data.rs +++ b/src/librustc/middle/borrowck/move_data.rs @@ -474,6 +474,24 @@ impl FlowedMoveData { } } + pub fn each_path_moved_by(&self, + id: ast::node_id, + f: &fn(&Move, @LoanPath) -> bool) + -> bool { + /*! + * Iterates through each path moved by `id` + */ + + for self.dfcx_moves.each_gen_bit_frozen(id) |index| { + let move = &self.move_data.moves[index]; + let moved_path = move.path; + if !f(move, self.move_data.path(moved_path).loan_path) { + return false; + } + } + return true; + } + pub fn each_move_of(&self, id: ast::node_id, loan_path: @LoanPath, diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 0baeb8ce57c6c..02f7294ffcd3b 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -49,23 +49,13 @@ pub fn check_crate(tcx: ty::ctxt, tcx.sess.abort_if_errors(); } -pub fn expr_is_non_moving_lvalue(cx: &MatchCheckCtxt, expr: &expr) -> bool { - if !ty::expr_is_lval(cx.tcx, cx.method_map, expr) { - return false; - } - - !cx.moves_map.contains(&expr.id) -} - pub fn check_expr(cx: @MatchCheckCtxt, ex: @expr, (s, v): ((), visit::vt<()>)) { visit::visit_expr(ex, (s, v)); match ex.node { expr_match(scrut, ref arms) => { // First, check legality of move bindings. - let is_non_moving_lvalue = expr_is_non_moving_lvalue(cx, ex); for arms.iter().advance |arm| { check_legality_of_move_bindings(cx, - is_non_moving_lvalue, arm.guard.is_some(), arm.pats); } @@ -758,11 +748,7 @@ pub fn check_local(cx: &MatchCheckCtxt, } // Check legality of move bindings. - let is_lvalue = match loc.node.init { - Some(init) => expr_is_non_moving_lvalue(cx, init), - None => true - }; - check_legality_of_move_bindings(cx, is_lvalue, false, [ loc.node.pat ]); + check_legality_of_move_bindings(cx, false, [ loc.node.pat ]); } pub fn check_fn(cx: &MatchCheckCtxt, @@ -821,7 +807,6 @@ pub fn is_refutable(cx: &MatchCheckCtxt, pat: &pat) -> bool { // Legality of move bindings checking pub fn check_legality_of_move_bindings(cx: &MatchCheckCtxt, - is_lvalue: bool, has_guard: bool, pats: &[@pat]) { let tcx = cx.tcx; @@ -861,11 +846,6 @@ pub fn check_legality_of_move_bindings(cx: &MatchCheckCtxt, tcx.sess.span_note( by_ref_span.get(), "by-ref binding occurs here"); - } else if is_lvalue { - tcx.sess.span_err( - p.span, - "cannot bind by-move when \ - matching an lvalue"); } }; diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index e054b84984d15..ec375eaba0e86 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -422,8 +422,8 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { loop_scopes: &mut ~[LoopScope]) { match decl.node { ast::decl_local(local) => { - self.walk_pat(local.node.pat, in_out, loop_scopes); self.walk_opt_expr(local.node.init, in_out, loop_scopes); + self.walk_pat(local.node.pat, in_out, loop_scopes); } ast::decl_item(_) => {} diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index fd36858ba6880..ac7805146e486 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -60,7 +60,7 @@ use syntax::print::pprust; #[deriving(Eq)] pub enum categorization { - cat_rvalue, // result of eval'ing some misc expr + cat_rvalue(ast::node_id), // temporary val, argument is its scope cat_static_item, cat_implicit_self, cat_copied_upvar(CopiedUpvar), // upvar copied into @fn or ~fn env @@ -350,7 +350,7 @@ impl mem_categorization_ctxt { // Convert a bare fn to a closure by adding NULL env. // Result is an rvalue. let expr_ty = ty::expr_ty_adjusted(self.tcx, expr); - self.cat_rvalue(expr, expr_ty) + self.cat_rvalue_node(expr, expr_ty) } Some( @@ -360,7 +360,7 @@ impl mem_categorization_ctxt { // Equivalent to &*expr or something similar. // Result is an rvalue. let expr_ty = ty::expr_ty_adjusted(self.tcx, expr); - self.cat_rvalue(expr, expr_ty) + self.cat_rvalue_node(expr, expr_ty) } Some( @@ -390,7 +390,7 @@ impl mem_categorization_ctxt { match expr.node { ast::expr_unary(_, ast::deref, e_base) => { if self.method_map.contains_key(&expr.id) { - return self.cat_rvalue(expr, expr_ty); + return self.cat_rvalue_node(expr, expr_ty); } let base_cmt = self.cat_expr(e_base); @@ -408,7 +408,7 @@ impl mem_categorization_ctxt { ast::expr_index(_, base, _) => { if self.method_map.contains_key(&expr.id) { - return self.cat_rvalue(expr, expr_ty); + return self.cat_rvalue_node(expr, expr_ty); } let base_cmt = self.cat_expr(base); @@ -433,7 +433,7 @@ impl mem_categorization_ctxt { ast::expr_match(*) | ast::expr_lit(*) | ast::expr_break(*) | ast::expr_mac(*) | ast::expr_again(*) | ast::expr_struct(*) | ast::expr_repeat(*) | ast::expr_inline_asm(*) => { - return self.cat_rvalue(expr, expr_ty); + return self.cat_rvalue_node(expr, expr_ty); } } } @@ -577,11 +577,24 @@ impl mem_categorization_ctxt { } } - pub fn cat_rvalue(&self, elt: N, expr_ty: ty::t) -> cmt { + pub fn cat_rvalue_node(&self, + node: N, + expr_ty: ty::t) -> cmt { + self.cat_rvalue(node.id(), + node.span(), + self.tcx.region_maps.cleanup_scope(node.id()), + expr_ty) + } + + pub fn cat_rvalue(&self, + cmt_id: ast::node_id, + span: span, + cleanup_scope_id: ast::node_id, + expr_ty: ty::t) -> cmt { @cmt_ { - id:elt.id(), - span:elt.span(), - cat:cat_rvalue, + id:cmt_id, + span:span, + cat:cat_rvalue(cleanup_scope_id), mutbl:McDeclared, ty:expr_ty } @@ -970,7 +983,7 @@ impl mem_categorization_ctxt { } for slice.iter().advance |&slice_pat| { let slice_ty = self.pat_ty(slice_pat); - let slice_cmt = self.cat_rvalue(pat, slice_ty); + let slice_cmt = self.cat_rvalue_node(pat, slice_ty); self.cat_pattern(slice_cmt, slice_pat, |x,y| op(x,y)); } for after.iter().advance |&after_pat| { @@ -1003,7 +1016,7 @@ impl mem_categorization_ctxt { cat_copied_upvar(_) => { ~"captured outer variable in a heap closure" } - cat_rvalue => { + cat_rvalue(*) => { ~"non-lvalue" } cat_local(_) => { @@ -1100,7 +1113,7 @@ impl cmt_ { //! determines how long the value in `self` remains live. match self.cat { - cat_rvalue | + cat_rvalue(*) | cat_static_item | cat_implicit_self | cat_copied_upvar(*) | @@ -1187,11 +1200,13 @@ impl Repr for categorization { match *self { cat_static_item | cat_implicit_self | - cat_rvalue | + cat_rvalue(*) | cat_copied_upvar(*) | cat_local(*) | cat_self(*) | - cat_arg(*) => fmt!("%?", *self), + cat_arg(*) => { + fmt!("%?", *self) + } cat_deref(cmt, derefs, ptr) => { fmt!("%s->(%s, %u)", cmt.cat.repr(tcx), ptr_sigil(ptr), derefs) @@ -1205,7 +1220,9 @@ impl Repr for categorization { fmt!("%s->(enum)", cmt.cat.repr(tcx)) } cat_stack_upvar(cmt) | - cat_discr(cmt, _) => cmt.cat.repr(tcx) + cat_discr(cmt, _) => { + cmt.cat.repr(tcx) + } } } } diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index f3d4abcdf310f..e9a73a513c8d8 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -190,10 +190,19 @@ enum UseMode { pub fn compute_moves(tcx: ty::ctxt, method_map: method_map, +<<<<<<< HEAD crate: &crate) -> MoveMaps { +||||||| merged common ancestors + crate: @crate) -> MoveMaps +{ +======= + crate: @crate) -> MoveMaps { +>>>>>>> Modify borrow checker to visit irrefutable patterns that appear in let visitor = visit::mk_vt(@visit::Visitor { + visit_fn: compute_modes_for_fn, visit_expr: compute_modes_for_expr, + visit_local: compute_modes_for_local, .. *visit::default_visitor() }); let visit_cx = VisitContext { @@ -220,9 +229,31 @@ pub fn moved_variable_node_id_from_def(def: def) -> Option { } } -// ______________________________________________________________________ +/////////////////////////////////////////////////////////////////////////// // Expressions +fn compute_modes_for_local<'a>(local: @local, + (cx, v): (VisitContext, + vt)) { + cx.use_pat(local.node.pat); + for local.node.init.iter().advance |&init| { + cx.use_expr(init, Read, v); + } +} + +fn compute_modes_for_fn(fk: &visit::fn_kind, + decl: &fn_decl, + body: &blk, + span: span, + id: node_id, + (cx, v): (VisitContext, + vt)) { + for decl.inputs.each |a| { + cx.use_pat(a.pat); + } + visit::visit_fn(fk, decl, body, span, id, (cx, v)); +} + fn compute_modes_for_expr(expr: @expr, (cx, v): (VisitContext, vt)) @@ -522,7 +553,10 @@ impl VisitContext { self.use_expr(base, comp_mode, visitor); } - expr_fn_block(_, ref body) => { + expr_fn_block(ref decl, ref body) => { + for decl.inputs.each |a| { + self.use_pat(a.pat); + } let cap_vars = self.compute_captures(expr.id); self.move_maps.capture_map.insert(expr.id, cap_vars); self.consume_block(body, visitor); @@ -580,13 +614,15 @@ impl VisitContext { * into itself or not based on its type and annotation. */ - do pat_bindings(self.tcx.def_map, pat) |bm, id, _span, _path| { + do pat_bindings(self.tcx.def_map, pat) |bm, id, _span, path| { let binding_moves = match bm { bind_by_ref(_) => false, bind_infer => { let pat_ty = ty::node_id_to_type(self.tcx, id); - debug!("pattern %? type is %s", - id, pat_ty.repr(self.tcx)); + debug!("pattern %? %s type is %s", + id, + ast_util::path_to_ident(path).repr(self.tcx), + pat_ty.repr(self.tcx)); ty::type_moves_by_default(self.tcx, pat_ty) } }; diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 1f7946576db5c..ac7a9db99e9ac 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -158,9 +158,9 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path, None => { fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| { - expected.map_default(~"", |&e| { + expected.map_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - e, actual)})}, + *e, actual)})}, Some(expected), ~"a structure pattern", None); fcx.write_error(pat.id); @@ -200,9 +200,9 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path, _ => { fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| { - expected.map_default(~"", |&e| { + expected.map_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - e, actual)})}, + *e, actual)})}, Some(expected), ~"an enum or structure pattern", None); fcx.write_error(pat.id); @@ -534,9 +534,9 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { _ => ty::terr_mismatch }; fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| { - expected.map_default(~"", |&e| { + expected.map_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - e, actual)})}, Some(expected), ~"tuple", Some(&type_error)); + *e, actual)})}, Some(expected), ~"tuple", Some(&type_error)); fcx.write_error(pat.id); } } @@ -583,9 +583,9 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { fcx.infcx().type_error_message_str_with_expected( pat.span, |expected, actual| { - expected.map_default(~"", |&e| { + expected.map_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - e, actual)})}, + *e, actual)})}, Some(expected), ~"a vector pattern", None); @@ -641,9 +641,9 @@ pub fn check_pointer_pat(pcx: &pat_ctxt, fcx.infcx().type_error_message_str_with_expected( span, |expected, actual| { - expected.map_default(~"", |&e| { + expected.map_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - e, actual)})}, + *e, actual)})}, Some(expected), fmt!("%s pattern", match pointer_kind { Managed => "an @-box", diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index e5248e01ed796..d59c8e5e894fb 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -350,10 +350,7 @@ pub fn resolve_type_vars_in_fn(fcx: @mut FnCtxt, self_info.self_id); } for decl.inputs.iter().advance |arg| { - do pat_util::pat_bindings(fcx.tcx().def_map, arg.pat) - |_bm, pat_id, span, _path| { - resolve_type_vars_for_node(wbcx, span, pat_id); - } + (visit.visit_pat)(arg.pat, (wbcx, visit)); // Privacy needs the type for the whole pattern, not just each binding if !pat_util::pat_is_binding(fcx.tcx().def_map, arg.pat) { resolve_type_vars_for_node(wbcx, arg.pat.span, arg.pat.id); From 541c45b0b77767641f3efb1d2814d148bbfdcd39 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 20 Jun 2013 15:26:54 -0400 Subject: [PATCH 10/20] Miscellaneous fixes and cleanup --- src/librustc/back/passes.rs | 6 +++--- src/librustc/driver/driver.rs | 1 - src/librustc/metadata/loader.rs | 4 +++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/librustc/back/passes.rs b/src/librustc/back/passes.rs index c1192707c1c15..f9dc88074d3b1 100644 --- a/src/librustc/back/passes.rs +++ b/src/librustc/back/passes.rs @@ -165,10 +165,10 @@ pub fn create_standard_passes(level: OptLevel) -> ~[~str] { } pub fn populate_pass_manager(sess: Session, pm: &mut PassManager, pass_list:&[~str]) { - for pass_list.iter().advance |&nm| { - match create_pass(nm) { + for pass_list.iter().advance |nm| { + match create_pass(*nm) { Some(p) => pm.add_pass(p), - None => sess.warn(fmt!("Unknown pass %s", nm)) + None => sess.warn(fmt!("Unknown pass %s", *nm)) } } } diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 3c50754744886..e8ef95b811e87 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -314,7 +314,6 @@ pub fn compile_rest(sess: Session, method_map: method_map, vtable_map: vtable_map, write_guard_map: write_guard_map, - moves_map: moves_map, capture_map: capture_map }; diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index 31577e472678e..9aefb8fdb5579 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -127,7 +127,9 @@ fn find_library_crate_aux( cx.diag.span_err( cx.span, fmt!("multiple matching crates for `%s`", crate_name)); cx.diag.handler().note("candidates:"); - for matches.iter().advance |&(ident, data)| { + for matches.iter().advance |pair| { + let ident = pair.first(); + let data = pair.second(); cx.diag.handler().note(fmt!("path: %s", ident)); let attrs = decoder::get_crate_attributes(data); note_linkage_attrs(cx.intr, cx.diag, attrs); From af453a33cc4ec8773ce869c4564d713a7ba60775 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 20 Jun 2013 15:27:10 -0400 Subject: [PATCH 11/20] This assert does not necessarily hold; sometimes we temporarily increase ref-count --- src/rt/boxed_region.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rt/boxed_region.cpp b/src/rt/boxed_region.cpp index a49b52bffe153..533a2a04755e9 100644 --- a/src/rt/boxed_region.cpp +++ b/src/rt/boxed_region.cpp @@ -40,8 +40,8 @@ rust_opaque_box *boxed_region::realloc(rust_opaque_box *box, size_t new_size) { // We also get called on the unique-vec-in-managed-heap path. - assert(box->ref_count == 1 || - box->ref_count == (size_t)(-2)); + // assert(box->ref_count == 1 || + // box->ref_count == (size_t)(-2)); size_t total_size = new_size + sizeof(rust_opaque_box); rust_opaque_box *new_box = From 59083d2c6aedcbab469e263850c717cd958c24e6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 21 Jun 2013 05:56:35 -0400 Subject: [PATCH 12/20] Address nits by @catamorphism --- src/libstd/ptr.rs | 2 +- src/rt/boxed_region.cpp | 4 ---- ...-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs | 8 ++++---- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/libstd/ptr.rs b/src/libstd/ptr.rs index add2bbd7d44f4..2b42c085009df 100644 --- a/src/libstd/ptr.rs +++ b/src/libstd/ptr.rs @@ -143,7 +143,7 @@ pub unsafe fn set_memory(dst: *mut T, c: u8, count: uint) { } /** - * Zeroes out `count` bytes of memory at `dst` + * Zeroes out `count * size_of::` bytes of memory at `dst` */ #[inline] #[cfg(not(stage0))] diff --git a/src/rt/boxed_region.cpp b/src/rt/boxed_region.cpp index 533a2a04755e9..012333b931ec7 100644 --- a/src/rt/boxed_region.cpp +++ b/src/rt/boxed_region.cpp @@ -39,10 +39,6 @@ rust_opaque_box *boxed_region::malloc(type_desc *td, size_t body_size) { rust_opaque_box *boxed_region::realloc(rust_opaque_box *box, size_t new_size) { - // We also get called on the unique-vec-in-managed-heap path. - // assert(box->ref_count == 1 || - // box->ref_count == (size_t)(-2)); - size_t total_size = new_size + sizeof(rust_opaque_box); rust_opaque_box *new_box = (rust_opaque_box*)backing_region->realloc(box, total_size); diff --git a/src/test/run-pass/borrowck-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs b/src/test/run-pass/borrowck-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs index c343258264748..5da7a6f2b56cc 100644 --- a/src/test/run-pass/borrowck-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs +++ b/src/test/run-pass/borrowck-wg-autoderef-and-autoborrowvec-combined-issue-6272.rs @@ -29,13 +29,13 @@ fn main() { let a = @mut 3i; - // let b = @mut [a]; - // let c = @mut [3]; + let b = @mut [a]; + let c = @mut [3]; // this should freeze `a` only let _x: &mut int = a; // hence these writes should not fail: - // b[0] = b[0]; - // c[0] = c[0]; + b[0] = b[0]; + c[0] = c[0]; } From 682e7467dd0c646a7d7bc1fd617e9629c98f82a1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 21 Jun 2013 06:31:11 -0400 Subject: [PATCH 13/20] Patch up some new errors from rustpkg --- src/librustpkg/package_source.rs | 2 +- src/librustpkg/path_util.rs | 12 ++++++------ src/librustpkg/util.rs | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/librustpkg/package_source.rs b/src/librustpkg/package_source.rs index b2f608bd352ae..54ad888e2ae8c 100644 --- a/src/librustpkg/package_source.rs +++ b/src/librustpkg/package_source.rs @@ -202,7 +202,7 @@ impl PkgSrc { crates: &[Crate], cfgs: &[~str], what: OutputType) { - for crates.iter().advance |&crate| { + for crates.iter().advance |crate| { let path = &src_dir.push_rel(&crate.file).normalize(); note(fmt!("build_crates: compiling %s", path.to_str())); note(fmt!("build_crates: destination dir is %s", dst_dir.to_str())); diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index b8f77ceececd7..c6f7735b204e4 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -71,8 +71,8 @@ pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, U_RWX) } pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool { let src_dir = workspace.push("src"); let dirs = os::list_dir(&src_dir); - for dirs.iter().advance |&p| { - let p = Path(p); + for dirs.iter().advance |p| { + let p = Path(copy *p); debug!("=> p = %s", p.to_str()); if !os::path_is_dir(&src_dir.push_rel(&p)) { loop; @@ -84,8 +84,8 @@ pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool { } else { let pf = p.filename(); - for pf.iter().advance |&pf| { - let f_ = copy pf; + for pf.iter().advance |pf| { + let f_ = copy *pf; let g = f_.to_str(); match split_version_general(g, '-') { Some((ref might_match, ref vers)) => { @@ -217,10 +217,10 @@ pub fn library_in_workspace(path: &LocalPath, short_name: &str, where: Target, debug!("lib_prefix = %s and lib_filetype = %s", lib_prefix, lib_filetype); let mut result_filename = None; - for dir_contents.iter().advance |&p| { + for dir_contents.iter().advance |p| { let mut which = 0; let mut hash = None; - let p_path = Path(p); + let p_path = Path(copy *p); let extension = p_path.filetype(); debug!("p = %s, p's extension is %?", p.to_str(), extension); match extension { diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 900ef4896ca11..da5c98680b919 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -194,7 +194,7 @@ pub fn compile_input(ctxt: &Ctx, Main => ~[] } + flags - + cfgs.flat_map(|&c| { ~[~"--cfg", c] }), + + cfgs.flat_map(|c| { ~[~"--cfg", copy *c] }), driver::optgroups()).get(); let options = @session::options { crate_type: crate_type, @@ -311,8 +311,8 @@ pub fn compile_crate(ctxt: &Ctx, pkg_id: &PkgId, what: OutputType) -> bool { debug!("compile_crate: crate=%s, dir=%s", crate.to_str(), dir.to_str()); debug!("compile_crate: short_name = %s, flags =...", pkg_id.to_str()); - for flags.iter().advance |&fl| { - debug!("+++ %s", fl); + for flags.iter().advance |fl| { + debug!("+++ %s", *fl); } compile_input(ctxt, pkg_id, crate, dir, flags, cfgs, opt, what) } From 50e95ea481af78516e3852687bc63d6d1a94dcd0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 21 Jun 2013 12:19:22 -0400 Subject: [PATCH 14/20] Fix pretty printer, which was ignoring `ref` in irrefutable patterns --- src/libsyntax/print/pprust.rs | 61 +++++++------------ src/test/bench/shootout-k-nucleotide-pipes.rs | 4 +- src/test/run-pass-fulldeps/qquote.rs | 2 +- 3 files changed, 26 insertions(+), 41 deletions(-) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index b545c56778e90..73ee8768ca302 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -147,7 +147,7 @@ pub fn ty_to_str(ty: &ast::Ty, intr: @ident_interner) -> ~str { } pub fn pat_to_str(pat: &ast::pat, intr: @ident_interner) -> ~str { - to_str(pat, print_irrefutable_pat, intr) + to_str(pat, print_pat, intr) } pub fn expr_to_str(e: &ast::expr, intr: @ident_interner) -> ~str { @@ -1240,7 +1240,7 @@ pub fn print_expr(s: @ps, expr: &ast::expr) { if first { first = false; } else { space(s.s); word_space(s, "|"); } - print_refutable_pat(s, *p); + print_pat(s, *p); } space(s.s); match arm.guard { @@ -1434,7 +1434,7 @@ pub fn print_expr(s: @ps, expr: &ast::expr) { } pub fn print_local_decl(s: @ps, loc: &ast::local) { - print_irrefutable_pat(s, loc.node.pat); + print_pat(s, loc.node.pat); match loc.node.ty.node { ast::ty_infer => (), _ => { word_space(s, ":"); print_type(s, &loc.node.ty); } @@ -1521,20 +1521,7 @@ pub fn print_path(s: @ps, path: &ast::Path, colons_before_params: bool) { print_path_(s, path, colons_before_params, &None) } -pub fn print_bounded_path(s: @ps, path: &ast::Path, - bounds: &Option>) { - print_path_(s, path, false, bounds) -} - -pub fn print_irrefutable_pat(s: @ps, pat: &ast::pat) { - print_pat(s, pat, false) -} - -pub fn print_refutable_pat(s: @ps, pat: &ast::pat) { - print_pat(s, pat, true) -} - -pub fn print_pat(s: @ps, pat: &ast::pat, refutable: bool) { +pub fn print_pat(s: @ps, pat: &ast::pat) { maybe_print_comment(s, pat.span.lo); let ann_node = node_pat(s, pat); (s.ann.pre)(ann_node); @@ -1543,20 +1530,18 @@ pub fn print_pat(s: @ps, pat: &ast::pat, refutable: bool) { match pat.node { ast::pat_wild => word(s.s, "_"), ast::pat_ident(binding_mode, ref path, sub) => { - if refutable { - match binding_mode { - ast::bind_by_ref(mutbl) => { - word_nbsp(s, "ref"); - print_mutability(s, mutbl); - } - ast::bind_infer => {} + match binding_mode { + ast::bind_by_ref(mutbl) => { + word_nbsp(s, "ref"); + print_mutability(s, mutbl); } + ast::bind_infer => {} } print_path(s, path, true); match sub { Some(p) => { word(s.s, "@"); - print_pat(s, p, refutable); + print_pat(s, p); } None => () } @@ -1569,7 +1554,7 @@ pub fn print_pat(s: @ps, pat: &ast::pat, refutable: bool) { if !args.is_empty() { popen(s); commasep(s, inconsistent, *args, - |s, &p| print_pat(s, p, refutable)); + |s, &p| print_pat(s, p)); pclose(s); } else { } } @@ -1578,16 +1563,16 @@ pub fn print_pat(s: @ps, pat: &ast::pat, refutable: bool) { ast::pat_struct(ref path, ref fields, etc) => { print_path(s, path, true); word(s.s, "{"); - fn print_field(s: @ps, f: &ast::field_pat, refutable: bool) { + fn print_field(s: @ps, f: &ast::field_pat) { cbox(s, indent_unit); print_ident(s, f.ident); word_space(s, ":"); - print_pat(s, f.pat, refutable); + print_pat(s, f.pat); end(s); } fn get_span(f: &ast::field_pat) -> codemap::span { return f.pat.span; } commasep_cmnt(s, consistent, *fields, - |s, f| print_field(s,f,refutable), + |s, f| print_field(s,f), get_span); if etc { if fields.len() != 0u { word_space(s, ","); } @@ -1597,7 +1582,7 @@ pub fn print_pat(s: @ps, pat: &ast::pat, refutable: bool) { } ast::pat_tup(ref elts) => { popen(s); - commasep(s, inconsistent, *elts, |s, &p| print_pat(s, p, refutable)); + commasep(s, inconsistent, *elts, |s, &p| print_pat(s, p)); if elts.len() == 1 { word(s.s, ","); } @@ -1605,15 +1590,15 @@ pub fn print_pat(s: @ps, pat: &ast::pat, refutable: bool) { } ast::pat_box(inner) => { word(s.s, "@"); - print_pat(s, inner, refutable); + print_pat(s, inner); } ast::pat_uniq(inner) => { word(s.s, "~"); - print_pat(s, inner, refutable); + print_pat(s, inner); } ast::pat_region(inner) => { word(s.s, "&"); - print_pat(s, inner, refutable); + print_pat(s, inner); } ast::pat_lit(e) => print_expr(s, e), ast::pat_range(begin, end) => { @@ -1625,16 +1610,16 @@ pub fn print_pat(s: @ps, pat: &ast::pat, refutable: bool) { ast::pat_vec(ref before, slice, ref after) => { word(s.s, "["); do commasep(s, inconsistent, *before) |s, &p| { - print_pat(s, p, refutable); + print_pat(s, p); } for slice.iter().advance |&p| { if !before.is_empty() { word_space(s, ","); } word(s.s, ".."); - print_pat(s, p, refutable); + print_pat(s, p); if !after.is_empty() { word_space(s, ","); } } do commasep(s, inconsistent, *after) |s, &p| { - print_pat(s, p, refutable); + print_pat(s, p); } word(s.s, "]"); } @@ -1888,7 +1873,7 @@ pub fn print_arg(s: @ps, input: &ast::arg) { word_space(s, "mut"); } match input.ty.node { - ast::ty_infer => print_irrefutable_pat(s, input.pat), + ast::ty_infer => print_pat(s, input.pat), _ => { match input.pat.node { ast::pat_ident(_, ref path, _) if @@ -1897,7 +1882,7 @@ pub fn print_arg(s: @ps, input: &ast::arg) { // Do nothing. } _ => { - print_irrefutable_pat(s, input.pat); + print_pat(s, input.pat); word(s.s, ":"); space(s.s); } diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index 974cdb0a0ef63..919c4daeb253b 100644 --- a/src/test/bench/shootout-k-nucleotide-pipes.rs +++ b/src/test/bench/shootout-k-nucleotide-pipes.rs @@ -56,8 +56,8 @@ fn sort_and_fmt(mm: &HashMap<~[u8], uint>, total: uint) -> ~str { let mut pairs = ~[]; // map -> [(k,%)] - for mm.iter().advance |(&key, &val)| { - pairs.push((key, pct(val, total))); + for mm.iter().advance |(key, &val)| { + pairs.push((copy *key, pct(val, total))); } let pairs_sorted = sortKV(pairs); diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs index 9a3ba32390c72..92344aae73e6d 100644 --- a/src/test/run-pass-fulldeps/qquote.rs +++ b/src/test/run-pass-fulldeps/qquote.rs @@ -68,7 +68,7 @@ fn main() { check_pp(ext_cx, *stmt, pprust::print_stmt, ~"let x = 20;"); let pat = quote_pat!(Some(_)); - check_pp(ext_cx, pat, pprust::print_refutable_pat, ~"Some(_)"); + check_pp(ext_cx, pat, pprust::print_pat, ~"Some(_)"); } From 0e81072ded014450cb471dac66b23bd05955ca0c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 22 Jun 2013 18:38:02 -0400 Subject: [PATCH 15/20] Move stats into an @mut stats --- src/librustc/middle/trans/context.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index ebaa317944284..2880c68c1e036 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -96,7 +96,7 @@ pub struct CrateContext { all_llvm_symbols: HashSet<@str>, tcx: ty::ctxt, maps: astencode::Maps, - stats: Stats, + stats: @mut Stats, upcalls: @upcall::Upcalls, tydesc_type: Type, int_type: Type, @@ -201,7 +201,7 @@ impl CrateContext { all_llvm_symbols: HashSet::new(), tcx: tcx, maps: maps, - stats: Stats { + stats: @mut Stats { n_static_tydescs: 0u, n_glues_created: 0u, n_null_glues: 0u, From ce602c66b8ff487ca74f074120419a18c9f25871 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 23 Jun 2013 19:54:32 -0400 Subject: [PATCH 16/20] Add llvm instrumentation --- src/librustc/middle/trans/_match.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index a9a3c9317b44f..f5bb075aafc21 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -1738,6 +1738,7 @@ pub fn store_local(bcx: block, * Generates code for a local variable declaration like * `let ;` or `let = `. */ + let _icx = bcx.insn_ctxt("match::store_local"); let mut bcx = bcx; return match opt_init_expr { @@ -1812,6 +1813,7 @@ pub fn store_arg(mut bcx: block, * if the argument type is `T`, then `llval` is a `T*`). In some * cases, this code may zero out the memory `llval` points at. */ + let _icx = bcx.insn_ctxt("match::store_arg"); // We always need to cleanup the argument as we exit the fn scope. // Note that we cannot do it before for fear of a fn like From 979d3a54f9e1eea483734059a2f594278787e16a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 24 Jun 2013 13:30:35 -0400 Subject: [PATCH 17/20] Correct merge failures --- src/libextra/fileinput.rs | 2 +- src/libextra/num/bigint.rs | 2 +- src/libextra/term.rs | 4 +- .../middle/borrowck/gather_loans/mod.rs | 2 +- src/librustc/middle/moves.rs | 11 +--- src/librustc/middle/trans/_match.rs | 9 ++- src/librustc/middle/trans/base.rs | 60 ++----------------- src/librustc/middle/trans/callee.rs | 5 +- src/librustc/middle/trans/meth.rs | 3 +- src/libstd/vec.rs | 6 +- src/libsyntax/print/pprust.rs | 7 ++- .../borrowck-move-out-of-struct-with-dtor.rs | 2 +- ...owck-move-out-of-tuple-struct-with-dtor.rs | 2 +- src/test/run-pass/reflect-visit-type.rs | 4 +- 14 files changed, 34 insertions(+), 85 deletions(-) diff --git a/src/libextra/fileinput.rs b/src/libextra/fileinput.rs index de6edd540948d..27c8051afac36 100644 --- a/src/libextra/fileinput.rs +++ b/src/libextra/fileinput.rs @@ -418,7 +418,7 @@ mod test { fn make_file(path : &Path, contents: &[~str]) { let file = io::file_writer(path, [io::Create, io::Truncate]).get(); - for contents.iter().advance |&str| { + for contents.iter().advance |str| { file.write_str(*str); file.write_char('\n'); } diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs index 918424748990a..5867b13f55656 100644 --- a/src/libextra/num/bigint.rs +++ b/src/libextra/num/bigint.rs @@ -1586,7 +1586,7 @@ mod biguint_tests { let &(ref n, ref rs) = num_pair; for rs.iter().advance |str_pair| { let &(ref radix, ref str) = str_pair; - assert_eq!(&n, &FromStrRadix::from_str_radix(*str, *radix).get()); + assert_eq!(n, &FromStrRadix::from_str_radix(*str, *radix).get()); } } diff --git a/src/libextra/term.rs b/src/libextra/term.rs index 5562662277576..cd226e2ad3267 100644 --- a/src/libextra/term.rs +++ b/src/libextra/term.rs @@ -119,8 +119,8 @@ impl Terminal { pub fn reset(&self) { let mut vars = Variables::new(); let s = do self.ti.strings.find_equiv(&("op")) - .map_consume_default(Err(~"can't find terminfo capability `op`")) |&op| { - expand(op, [], &mut vars) + .map_consume_default(Err(~"can't find terminfo capability `op`")) |op| { + expand(copy *op, [], &mut vars) }; if s.is_ok() { self.out.write(s.unwrap()); diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index 86baf53528427..23451e0f36ea0 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -617,7 +617,7 @@ impl GatherLoanCtxt { */ let mc_ctxt = self.bccx.mc_ctxt(); - for decl.inputs.each |arg| { + for decl.inputs.iter().advance |arg| { let arg_ty = ty::node_id_to_type(self.tcx(), arg.pat.id); let arg_cmt = mc_ctxt.cat_rvalue( diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index e9a73a513c8d8..07bdee07c0feb 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -190,15 +190,8 @@ enum UseMode { pub fn compute_moves(tcx: ty::ctxt, method_map: method_map, -<<<<<<< HEAD crate: &crate) -> MoveMaps { -||||||| merged common ancestors - crate: @crate) -> MoveMaps -{ -======= - crate: @crate) -> MoveMaps { ->>>>>>> Modify borrow checker to visit irrefutable patterns that appear in let visitor = visit::mk_vt(@visit::Visitor { visit_fn: compute_modes_for_fn, visit_expr: compute_modes_for_expr, @@ -248,7 +241,7 @@ fn compute_modes_for_fn(fk: &visit::fn_kind, id: node_id, (cx, v): (VisitContext, vt)) { - for decl.inputs.each |a| { + for decl.inputs.iter().advance |a| { cx.use_pat(a.pat); } visit::visit_fn(fk, decl, body, span, id, (cx, v)); @@ -554,7 +547,7 @@ impl VisitContext { } expr_fn_block(ref decl, ref body) => { - for decl.inputs.each |a| { + for decl.inputs.iter().advance |a| { self.use_pat(a.pat); } let cap_vars = self.compute_captures(expr.id); diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index f5bb075aafc21..74f1e372c078f 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -1738,7 +1738,7 @@ pub fn store_local(bcx: block, * Generates code for a local variable declaration like * `let ;` or `let = `. */ - let _icx = bcx.insn_ctxt("match::store_local"); + let _icx = push_ctxt("match::store_local"); let mut bcx = bcx; return match opt_init_expr { @@ -1813,7 +1813,7 @@ pub fn store_arg(mut bcx: block, * if the argument type is `T`, then `llval` is a `T*`). In some * cases, this code may zero out the memory `llval` points at. */ - let _icx = bcx.insn_ctxt("match::store_arg"); + let _icx = push_ctxt("match::store_arg"); // We always need to cleanup the argument as we exit the fn scope. // Note that we cannot do it before for fear of a fn like @@ -1882,10 +1882,9 @@ fn bind_irrefutable_pat(bcx: block, * - binding_mode: is this for an argument or a local variable? */ - debug!("bind_irrefutable_pat(bcx=%s, pat=%s, val=%s, binding_mode=%?)", + debug!("bind_irrefutable_pat(bcx=%s, pat=%s, binding_mode=%?)", bcx.to_str(), pat_to_str(pat, bcx.sess().intr()), - val_str(bcx.ccx().tn, val), binding_mode); if bcx.sess().asm_comments() { @@ -1895,7 +1894,7 @@ fn bind_irrefutable_pat(bcx: block, let _indenter = indenter(); - let _icx = bcx.insn_ctxt("alt::bind_irrefutable_pat"); + let _icx = push_ctxt("alt::bind_irrefutable_pat"); let mut bcx = bcx; let tcx = bcx.tcx(); let ccx = bcx.ccx(); diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 75d9f89a8d7d5..c8117ed64a73b 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -112,8 +112,8 @@ impl Drop for _InsnCtxt { fn drop(&self) { unsafe { do local_data::local_data_modify(task_local_insn_key) |c| { - do c.map_consume |@ctx| { - let mut ctx = ctx; + do c.map_consume |ctx| { + let mut ctx = copy *ctx; ctx.pop(); @ctx } @@ -126,8 +126,8 @@ pub fn push_ctxt(s: &'static str) -> _InsnCtxt { debug!("new InsnCtxt: %s", s); unsafe { do local_data::local_data_modify(task_local_insn_key) |c| { - do c.map_consume |@ctx| { - let mut ctx = ctx; + do c.map_consume |ctx| { + let mut ctx = copy *ctx; ctx.push(s); @ctx } @@ -1438,54 +1438,6 @@ pub fn block_locals(b: &ast::blk, it: &fn(@ast::local)) { } } -<<<<<<< variant A -pub fn alloc_local(cx: block, local: &ast::local) -> block { - let _icx = push_ctxt("alloc_local"); - let t = node_id_type(cx, local.node.id); - let simple_name = match local.node.pat.node { - ast::pat_ident(_, ref pth, None) => Some(path_to_ident(pth)), - _ => None - }; - let val = alloc_ty(cx, t); - if cx.sess().opts.debuginfo { - for simple_name.iter().advance |name| { - str::as_c_str(cx.ccx().sess.str_of(*name), |buf| { - unsafe { - llvm::LLVMSetValueName(val, buf) - } - }); - } - } - cx.fcx.lllocals.insert(local.node.id, val); - cx -} - - ->>>>>>> variant B -####### Ancestor -pub fn alloc_local(cx: block, local: @ast::local) -> block { - let _icx = push_ctxt("alloc_local"); - let t = node_id_type(cx, local.node.id); - let simple_name = match local.node.pat.node { - ast::pat_ident(_, pth, None) => Some(path_to_ident(pth)), - _ => None - }; - let val = alloc_ty(cx, t); - if cx.sess().opts.debuginfo { - for simple_name.iter().advance |name| { - str::as_c_str(cx.ccx().sess.str_of(*name), |buf| { - unsafe { - llvm::LLVMSetValueName(val, buf) - } - }); - } - } - cx.fcx.lllocals.insert(local.node.id, val); - cx -} - - -======= end pub fn with_cond(bcx: block, val: ValueRef, f: &fn(block) -> block) -> block { let _icx = push_ctxt("with_cond"); let next_cx = base::sub_block(bcx, "next"); @@ -1763,7 +1715,7 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt, let self_val = if slf.is_copy && datum::appropriate_mode(bcx.tcx(), slf.t).is_by_value() { let tmp = BitCast(bcx, slf.v, type_of(bcx.ccx(), slf.t)); - let alloc = alloc_ty(bcx, slf.t); + let alloc = alloc_ty(bcx, slf.t, "__self"); Store(bcx, tmp, alloc); alloc } else { @@ -3030,7 +2982,7 @@ pub fn trans_crate(sess: session::Session, } } if ccx.sess.count_llvm_insns() { - for ccx.stats.llvm_insns.each |k, v| { + for ccx.stats.llvm_insns.iter().advance |(k, v)| { io::println(fmt!("%-7u %s", *v, *k)); } } diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 216338e111787..22adc4aa24b65 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -873,10 +873,10 @@ pub fn trans_arg_expr(bcx: block, // &arg_expr.id); debug!("by ref arg with type %s, storing to scratch", bcx.ty_to_str(arg_datum.ty)); - let scratch = scratch_datum(bcx, arg_datum.ty, false); + let scratch = scratch_datum(bcx, arg_datum.ty, + "__self", false); arg_datum.store_to_datum(bcx, - arg_expr.id, INIT, scratch); @@ -897,7 +897,6 @@ pub fn trans_arg_expr(bcx: block, "__arg", false); arg_datum.store_to_datum(bcx, - arg_expr.id, INIT, scratch); diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 14cc822b5a571..0914e61d58f33 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -614,7 +614,8 @@ pub fn trans_trait_callee_from_llval(bcx: block, } llself = PointerCast(bcx, llself, Type::opaque_box(ccx).ptr_to()); - let scratch = scratch_datum(bcx, ty::mk_opaque_box(bcx.tcx()), false); + let scratch = scratch_datum(bcx, ty::mk_opaque_box(bcx.tcx()), + "__trait_callee", false); Store(bcx, llself, scratch.val); scratch.add_clean(bcx); diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index b4e891414f61c..c546be6313825 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -1276,7 +1276,7 @@ impl OwnedVector for ~[T] { ln => { let valptr = ptr::to_mut_unsafe_ptr(&mut self[ln - 1u]); unsafe { - raw::set_len(v, ln - 1u); + raw::set_len(self, ln - 1u); ptr::read_ptr(valptr) } } @@ -1408,7 +1408,7 @@ impl OwnedVector for ~[T] { unsafe { // This loop is optimized out for non-drop types. for uint::range(newlen, oldlen) |i| { - ptr::read_and_zero_ptr(ptr::mut_offset(p, i)) + ptr::read_and_zero_ptr(ptr::mut_offset(p, i)); } } } @@ -1556,7 +1556,7 @@ impl OwnedEqVector for ~[T] { * Remove consecutive repeated elements from a vector; if the vector is * sorted, this removes all duplicates. */ - pub fn dedup(&mut self) { + pub fn dedup(&mut self) { unsafe { // Although we have a mutable reference to `self`, we cannot make // *arbitrary* changes. There exists the possibility that this diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 73ee8768ca302..f9504a696ce5e 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1521,7 +1521,12 @@ pub fn print_path(s: @ps, path: &ast::Path, colons_before_params: bool) { print_path_(s, path, colons_before_params, &None) } -pub fn print_pat(s: @ps, pat: &ast::pat) { +pub fn print_bounded_path(s: @ps, path: &ast::Path, + bounds: &Option>) { + print_path_(s, path, false, bounds) +} + +pub fn print_pat(s: @ps, pat: @ast::pat) { maybe_print_comment(s, pat.span.lo); let ann_node = node_pat(s, pat); (s.ann.pre)(ann_node); diff --git a/src/test/compile-fail/borrowck-move-out-of-struct-with-dtor.rs b/src/test/compile-fail/borrowck-move-out-of-struct-with-dtor.rs index 827e35e0c8302..4407329f49775 100644 --- a/src/test/compile-fail/borrowck-move-out-of-struct-with-dtor.rs +++ b/src/test/compile-fail/borrowck-move-out-of-struct-with-dtor.rs @@ -1,6 +1,6 @@ struct S {f:~str} impl Drop for S { - fn finalize(&self) { println(self.f); } + fn drop(&self) { println(self.f); } } fn move_in_match() { diff --git a/src/test/compile-fail/borrowck-move-out-of-tuple-struct-with-dtor.rs b/src/test/compile-fail/borrowck-move-out-of-tuple-struct-with-dtor.rs index 6013999d835d4..400a4f07951fc 100644 --- a/src/test/compile-fail/borrowck-move-out-of-tuple-struct-with-dtor.rs +++ b/src/test/compile-fail/borrowck-move-out-of-tuple-struct-with-dtor.rs @@ -1,6 +1,6 @@ struct S(~str); impl Drop for S { - fn finalize(&self) { println(**self); } + fn drop(&self) { println(**self); } } fn move_in_match() { diff --git a/src/test/run-pass/reflect-visit-type.rs b/src/test/run-pass/reflect-visit-type.rs index 4ce229526ffba..f8c369c2e5f7e 100644 --- a/src/test/run-pass/reflect-visit-type.rs +++ b/src/test/run-pass/reflect-visit-type.rs @@ -163,8 +163,8 @@ pub fn main() { visit_ty::(vv); visit_ty::<~[int]>(vv); - for v.types.iter().advance |&s| { - println(fmt!("type: %s", s)); + for v.types.iter().advance |s| { + println(fmt!("type: %s", copy *s)); } assert_eq!((*v.types).clone(), ~[~"bool", ~"int", ~"i8", ~"i16", ~"[", ~"int", ~"]"]); } From a6d64df6720328289ccde67a8685b79ad6780a9d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 1 Jul 2013 14:45:24 -0400 Subject: [PATCH 18/20] Correct illegal pattern in windows-only code --- src/libstd/run.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/run.rs b/src/libstd/run.rs index b7bec95e6554e..17dc604a17858 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -744,8 +744,8 @@ fn with_envp(env: Option<&[(~str, ~str)]>, cb: &fn(*mut c_void) -> T) -> T { match env { Some(es) => { let mut blk = ~[]; - for es.iter().advance |&(k, v)| { - let kv = fmt!("%s=%s", k, v); + for es.iter().advance |pair| { + let kv = fmt!("%s=%s", pair.first(), pair.second()); blk.push_all(kv.as_bytes_with_null_consume()); } blk.push(0); From b5fc4ae9189f8ffe52fd6ec7b228d803f594b48b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 1 Jul 2013 19:59:53 -0400 Subject: [PATCH 19/20] Correct match-drop-strs-issue-4541 when used in check-fast --- src/test/run-pass/match-drop-strs-issue-4541.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/run-pass/match-drop-strs-issue-4541.rs b/src/test/run-pass/match-drop-strs-issue-4541.rs index ec65f36dc06f5..2a629b62534ec 100644 --- a/src/test/run-pass/match-drop-strs-issue-4541.rs +++ b/src/test/run-pass/match-drop-strs-issue-4541.rs @@ -3,9 +3,10 @@ // or double-free, as we were wont to do in the past. use std::io; +use std::os; fn parse_args() -> ~str { - let args = std::os::args(); + let args = os::args(); let mut n = 0; while n < args.len() { From 0c6d02f391aa668b2ead91e8a4ed545475ac2c90 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 8 Jul 2013 11:05:52 -0400 Subject: [PATCH 20/20] Correct merge errors --- src/librustc/middle/trans/_match.rs | 8 ++++---- src/librustc/middle/trans/base.rs | 16 ++++++++++------ src/librustc/middle/typeck/coherence.rs | 4 ++-- src/libstd/vec.rs | 2 +- src/libsyntax/ext/deriving/generic.rs | 8 ++++---- src/libsyntax/ext/pipes/pipec.rs | 2 +- src/libsyntax/parse/parser.rs | 2 +- src/libsyntax/print/pprust.rs | 2 +- 8 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 74f1e372c078f..d5d0cde1ee0a0 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -1842,7 +1842,7 @@ pub fn store_arg(mut bcx: block, fn mk_binding_alloca(mut bcx: block, p_id: ast::node_id, - path: @ast::Path, + path: &ast::Path, binding_mode: IrrefutablePatternBindingMode, populate: &fn(block, ty::t, ValueRef) -> block) -> block { let var_ty = node_id_type(bcx, p_id); @@ -1899,7 +1899,7 @@ fn bind_irrefutable_pat(bcx: block, let tcx = bcx.tcx(); let ccx = bcx.ccx(); match pat.node { - ast::pat_ident(pat_binding_mode, path, inner) => { + ast::pat_ident(pat_binding_mode, ref path, inner) => { if pat_is_binding(tcx.def_map, pat) { // Allocate the stack slot where the value of this // binding will live and place it into the appropriate @@ -2017,9 +2017,9 @@ fn bind_irrefutable_pat(bcx: block, return bcx; } -fn simple_identifier(pat: @ast::pat) -> Option<@ast::Path> { +fn simple_identifier<'a>(pat: &'a ast::pat) -> Option<&'a ast::Path> { match pat.node { - ast::pat_ident(ast::bind_infer, path, None) => { + ast::pat_ident(ast::bind_infer, ref path, None) => { Some(path) } _ => { diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index c8117ed64a73b..80fc3803ae732 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1969,17 +1969,17 @@ pub fn trans_tuple_struct(ccx: @mut CrateContext, trait IdAndTy { fn id(&self) -> ast::node_id; - fn ty(&self) -> @ast::Ty; + fn ty<'a>(&'a self) -> &'a ast::Ty; } impl IdAndTy for ast::variant_arg { fn id(&self) -> ast::node_id { self.id } - fn ty(&self) -> @ast::Ty { self.ty } + fn ty<'a>(&'a self) -> &'a ast::Ty { &self.ty } } impl IdAndTy for @ast::struct_field { fn id(&self) -> ast::node_id { self.node.id } - fn ty(&self) -> @ast::Ty { self.node.ty } + fn ty<'a>(&'a self) -> &'a ast::Ty { &self.node.ty } } pub fn trans_enum_variant_or_tuple_like_struct( @@ -1994,7 +1994,7 @@ pub fn trans_enum_variant_or_tuple_like_struct( let fn_args = do args.map |varg| { ast::arg { is_mutbl: false, - ty: varg.ty(), + ty: copy *varg.ty(), pat: ast_util::ident_to_pat( ccx.tcx.sess.next_node_id(), codemap::dummy_sp(), @@ -2977,8 +2977,12 @@ pub fn trans_crate(sess: session::Session, do sort::quick_sort(ccx.stats.fn_stats) |&(_, _, insns_a), &(_, _, insns_b)| { insns_a > insns_b } - for ccx.stats.fn_stats.iter().advance |&(name, ms, insns)| { - io::println(fmt!("%u insns, %u ms, %s", insns, ms, name)); + for ccx.stats.fn_stats.iter().advance |tuple| { + match *tuple { + (ref name, ms, insns) => { + io::println(fmt!("%u insns, %u ms, %s", insns, ms, *name)); + } + } } } if ccx.sess.count_llvm_insns() { diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 473d5b8e6e880..7ee731d4f46b4 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -209,7 +209,7 @@ impl CoherenceChecker { match item.node { item_impl(_, ref opt_trait, _, _) => { let opt_trait : ~[trait_ref] = opt_trait.iter() - .transform(|&x| x) + .transform(|x| copy *x) .collect(); self.check_implementation(item, opt_trait); } @@ -270,7 +270,7 @@ impl CoherenceChecker { // We only want to generate one Impl structure. When we generate one, // we store it here so that we don't recreate it. let mut implementation_opt = None; - for associated_traits.iter().advance |&associated_trait| { + for associated_traits.iter().advance |associated_trait| { let trait_ref = ty::node_id_to_trait_ref( self.crate_context.tcx, diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index c546be6313825..a69ffca026b86 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -1277,7 +1277,7 @@ impl OwnedVector for ~[T] { let valptr = ptr::to_mut_unsafe_ptr(&mut self[ln - 1u]); unsafe { raw::set_len(self, ln - 1u); - ptr::read_ptr(valptr) + Some(ptr::read_ptr(valptr)) } } } diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs index d3554d6b27cd4..3bc16477c808a 100644 --- a/src/libsyntax/ext/deriving/generic.rs +++ b/src/libsyntax/ext/deriving/generic.rs @@ -519,8 +519,8 @@ impl<'self> MethodDef<'self> { // create the generics that aren't for Self let fn_generics = self.generics.to_generics(cx, span, type_ident, generics); - let args = do arg_types.map |&(id, ty)| { - cx.arg(span, id, ty) + let args = do arg_types.map |pair| { + cx.arg(span, pair.first(), pair.second()) }; let ret_type = self.get_ret_ty(cx, span, generics, type_ident); @@ -896,8 +896,8 @@ pub fn create_subpatterns(cx: @ExtCtxt, field_paths: ~[ast::Path], mutbl: ast::mutability) -> ~[@ast::pat] { - do field_paths.map |&path| { - cx.pat(span, ast::pat_ident(ast::bind_by_ref(mutbl), path, None)) + do field_paths.map |path| { + cx.pat(span, ast::pat_ident(ast::bind_by_ref(mutbl), copy *path, None)) } } diff --git a/src/libsyntax/ext/pipes/pipec.rs b/src/libsyntax/ext/pipes/pipec.rs index 98fc9aa61784d..478c086199011 100644 --- a/src/libsyntax/ext/pipes/pipec.rs +++ b/src/libsyntax/ext/pipes/pipec.rs @@ -137,7 +137,7 @@ impl gen_send for message { let arg_names = vec::from_fn(tys.len(), |i| "x_" + i.to_str()); let args_ast: ~[ast::arg] = arg_names.iter().zip(tys.iter()) - .transform(|(&n, t)| cx.arg(span, cx.ident_of(n), copy *t)).collect(); + .transform(|(n, t)| cx.arg(span, cx.ident_of(*n), copy *t)).collect(); let args_ast = vec::append( ~[cx.arg(span, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c43b350abdbf7..8666c84bbefe1 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3914,7 +3914,7 @@ impl Parser { }; let full_path = full_path.normalize(); - let maybe_i = do self.sess.included_mod_stack.iter().position |&p| { p == full_path }; + let maybe_i = do self.sess.included_mod_stack.iter().position |p| { *p == full_path }; match maybe_i { Some(i) => { let stack = &self.sess.included_mod_stack; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index f9504a696ce5e..c37108536154d 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1526,7 +1526,7 @@ pub fn print_bounded_path(s: @ps, path: &ast::Path, print_path_(s, path, false, bounds) } -pub fn print_pat(s: @ps, pat: @ast::pat) { +pub fn print_pat(s: @ps, pat: &ast::pat) { maybe_print_comment(s, pat.span.lo); let ann_node = node_pat(s, pat); (s.ann.pre)(ann_node);