auto merge of #7262 : nikomatsakis/rust/ref-bindings-in-irrefut-patterns, r=catamorphism
Correct treatment of irrefutable patterns. The old code was wrong in many, many ways. `ref` bindings didn't work, it sometimes copied when it should have moved, the borrow checker didn't even look at such patterns at all, we weren't consistent about preventing values with destructors from being pulled apart, etc. Fixes #3224. Fixes #3225. Fixes #3255. Fixes #6225. Fixes #6386. r? @catamorphism
This commit is contained in:
commit
a48ca3290d
72 changed files with 1140 additions and 696 deletions
|
|
@ -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);
|
||||
|
|
|
|||
16
src/test/compile-fail/borrowck-move-in-irrefut-pat.rs
Normal file
16
src/test/compile-fail/borrowck-move-in-irrefut-pat.rs
Normal file
|
|
@ -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() {}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
struct S {f:~str}
|
||||
impl Drop for S {
|
||||
fn drop(&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() {}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
struct S(~str);
|
||||
impl Drop for S {
|
||||
fn drop(&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() {}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
|
|||
11
src/test/compile-fail/regions-ref-in-fn-arg.rs
Normal file
11
src/test/compile-fail/regions-ref-in-fn-arg.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fn arg_item(~ref x: ~int) -> &'static int {
|
||||
x //~^ ERROR borrowed value does not live long enough
|
||||
}
|
||||
|
||||
fn with<R>(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() {}
|
||||
|
|
@ -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(_)");
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
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() {}
|
||||
|
|
@ -28,12 +28,12 @@
|
|||
|
||||
|
||||
fn main() {
|
||||
let a = @mut [3i];
|
||||
let a = @mut 3i;
|
||||
let b = @mut [a];
|
||||
let c = @mut b;
|
||||
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];
|
||||
|
|
|
|||
20
src/test/run-pass/func-arg-incomplete-pattern.rs
Normal file
20
src/test/run-pass/func-arg-incomplete-pattern.rs
Normal file
|
|
@ -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);
|
||||
}
|
||||
24
src/test/run-pass/func-arg-ref-pattern.rs
Normal file
24
src/test/run-pass/func-arg-ref-pattern.rs
Normal file
|
|
@ -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);
|
||||
}
|
||||
10
src/test/run-pass/func-arg-wild-pattern.rs
Normal file
10
src/test/run-pass/func-arg-wild-pattern.rs
Normal file
|
|
@ -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);
|
||||
}
|
||||
5
src/test/run-pass/let-destruct-ref.rs
Normal file
5
src/test/run-pass/let-destruct-ref.rs
Normal file
|
|
@ -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()));
|
||||
}
|
||||
27
src/test/run-pass/match-drop-strs-issue-4541.rs
Normal file
27
src/test/run-pass/match-drop-strs-issue-4541.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// 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;
|
||||
use std::os;
|
||||
|
||||
fn parse_args() -> ~str {
|
||||
let args = 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());
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,8 +163,8 @@ pub fn main() {
|
|||
visit_ty::<i16>(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", ~"]"]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue