about summary refs log tree commit diff
path: root/src/test
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-08-14 16:36:19 +0000
committerbors <bors@rust-lang.org>2014-08-14 16:36:19 +0000
commit404978ea722c0257cc763540c93243e8a21f82ed (patch)
treec6106879c326924dc3d39ce71c0a797901bafe04 /src/test
parent56b86aaf35d96ec8cf8555205426eaed62427963 (diff)
parent8d272321417df3a954802e42a66adda87ade5a49 (diff)
downloadrust-404978ea722c0257cc763540c93243e8a21f82ed.tar.gz
rust-404978ea722c0257cc763540c93243e8a21f82ed.zip
auto merge of #16122 : pcwalton/rust/lifetimes-in-unboxed-closures, r=pnkfelix
This patch primarily does two things: (1) it prevents lifetimes from
leaking out of unboxed closures; (2) it allows unboxed closure type
notation, call notation, and construction notation to construct closures
matching any of the three traits.

This breaks code that looked like:

    let mut f;
    {
        let x = &5i;
        f = |&mut:| *x + 10;
    }

Change this code to avoid having a reference escape. For example:

    {
        let x = &5i;
        let mut f; // <-- move here to avoid dangling reference
        f = |&mut:| *x + 10;
    }

I believe this is enough to consider unboxed closures essentially
implemented. Further issues (for example, higher-rank lifetimes) should
be filed as followups.

Closes #14449.

[breaking-change]

r? @pnkfelix
Diffstat (limited to 'src/test')
-rw-r--r--src/test/compile-fail/borrowck-unboxed-closures.rs29
-rw-r--r--src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs24
-rw-r--r--src/test/compile-fail/unboxed-closures-wrong-trait.rs22
-rw-r--r--src/test/run-pass/unboxed-closures-all-traits.rs31
-rw-r--r--src/test/run-pass/unboxed-closures-drop.rs127
-rw-r--r--src/test/run-pass/unboxed-closures-single-word-env.rs34
6 files changed, 267 insertions, 0 deletions
diff --git a/src/test/compile-fail/borrowck-unboxed-closures.rs b/src/test/compile-fail/borrowck-unboxed-closures.rs
new file mode 100644
index 00000000000..d822bb22e2a
--- /dev/null
+++ b/src/test/compile-fail/borrowck-unboxed-closures.rs
@@ -0,0 +1,29 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(overloaded_calls)]
+
+fn a<F:|&: int, int| -> int>(mut f: F) {
+    let g = &mut f;
+    f(1, 2);    //~ ERROR cannot borrow `f` as immutable
+    //~^ ERROR cannot borrow `f` as immutable
+}
+
+fn b<F:|&mut: int, int| -> int>(f: F) {
+    f(1, 2);    //~ ERROR cannot borrow immutable argument
+}
+
+fn c<F:|: int, int| -> int>(f: F) {
+    f(1, 2);
+    f(1, 2);    //~ ERROR use of moved value
+}
+
+fn main() {}
+
diff --git a/src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs b/src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs
new file mode 100644
index 00000000000..1c590db11e3
--- /dev/null
+++ b/src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs
@@ -0,0 +1,24 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(unboxed_closure_sugar, unboxed_closures, overloaded_calls)]
+
+use std::ops::FnMut;
+
+fn main() {
+    let mut f;
+    {
+        let c = 1;
+        let c_ref = &c;
+        f = |&mut: a: int, b: int| { a + b + *c_ref };
+        //~^ ERROR cannot infer an appropriate lifetime
+    }
+}
+
diff --git a/src/test/compile-fail/unboxed-closures-wrong-trait.rs b/src/test/compile-fail/unboxed-closures-wrong-trait.rs
new file mode 100644
index 00000000000..50d90c6200e
--- /dev/null
+++ b/src/test/compile-fail/unboxed-closures-wrong-trait.rs
@@ -0,0 +1,22 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(lang_items, overloaded_calls, unboxed_closures)]
+
+fn c<F:|: int, int| -> int>(f: F) -> int {
+    f(5, 6)
+}
+
+fn main() {
+    let z: int = 7;
+    assert_eq!(c(|&: x: int, y| x + y + z), 10);
+    //~^ ERROR failed to find an implementation
+}
+
diff --git a/src/test/run-pass/unboxed-closures-all-traits.rs b/src/test/run-pass/unboxed-closures-all-traits.rs
new file mode 100644
index 00000000000..c362a83e60c
--- /dev/null
+++ b/src/test/run-pass/unboxed-closures-all-traits.rs
@@ -0,0 +1,31 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(lang_items, overloaded_calls, unboxed_closures)]
+
+fn a<F:|&: int, int| -> int>(f: F) -> int {
+    f(1, 2)
+}
+
+fn b<F:|&mut: int, int| -> int>(mut f: F) -> int {
+    f(3, 4)
+}
+
+fn c<F:|: int, int| -> int>(f: F) -> int {
+    f(5, 6)
+}
+
+fn main() {
+    let z: int = 7;
+    assert_eq!(a(|&: x: int, y| x + y + z), 10);
+    assert_eq!(b(|&mut: x: int, y| x + y + z), 14);
+    assert_eq!(c(|: x: int, y| x + y + z), 18);
+}
+
diff --git a/src/test/run-pass/unboxed-closures-drop.rs b/src/test/run-pass/unboxed-closures-drop.rs
new file mode 100644
index 00000000000..f20dddcae54
--- /dev/null
+++ b/src/test/run-pass/unboxed-closures-drop.rs
@@ -0,0 +1,127 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// A battery of tests to ensure destructors of unboxed closure environments
+// run at the right times.
+
+#![feature(overloaded_calls, unboxed_closures)]
+
+static mut DROP_COUNT: uint = 0;
+
+fn drop_count() -> uint {
+    unsafe {
+        DROP_COUNT
+    }
+}
+
+struct Droppable {
+    x: int,
+}
+
+impl Droppable {
+    fn new() -> Droppable {
+        Droppable {
+            x: 1
+        }
+    }
+}
+
+impl Drop for Droppable {
+    fn drop(&mut self) {
+        unsafe {
+            DROP_COUNT += 1
+        }
+    }
+}
+
+fn a<F:|&: int, int| -> int>(f: F) -> int {
+    f(1, 2)
+}
+
+fn b<F:|&mut: int, int| -> int>(mut f: F) -> int {
+    f(3, 4)
+}
+
+fn c<F:|: int, int| -> int>(f: F) -> int {
+    f(5, 6)
+}
+
+fn test_fn() {
+    {
+        a(|&: a: int, b| { a + b });
+    }
+    assert_eq!(drop_count(), 0);
+
+    {
+        let z = &Droppable::new();
+        a(|&: a: int, b| { z; a + b });
+        assert_eq!(drop_count(), 0);
+    }
+    assert_eq!(drop_count(), 1);
+
+    {
+        let z = &Droppable::new();
+        let zz = &Droppable::new();
+        a(|&: a: int, b| { z; zz; a + b });
+        assert_eq!(drop_count(), 1);
+    }
+    assert_eq!(drop_count(), 3);
+}
+
+fn test_fn_mut() {
+    {
+        b(|&mut: a: int, b| { a + b });
+    }
+    assert_eq!(drop_count(), 3);
+
+    {
+        let z = &Droppable::new();
+        b(|&mut: a: int, b| { z; a + b });
+        assert_eq!(drop_count(), 3);
+    }
+    assert_eq!(drop_count(), 4);
+
+    {
+        let z = &Droppable::new();
+        let zz = &Droppable::new();
+        b(|&mut: a: int, b| { z; zz; a + b });
+        assert_eq!(drop_count(), 4);
+    }
+    assert_eq!(drop_count(), 6);
+}
+
+fn test_fn_once() {
+    {
+        c(|: a: int, b| { a + b });
+    }
+    assert_eq!(drop_count(), 6);
+
+    {
+        let z = Droppable::new();
+        c(|: a: int, b| { z; a + b });
+        assert_eq!(drop_count(), 7);
+    }
+    assert_eq!(drop_count(), 7);
+
+    {
+        let z = Droppable::new();
+        let zz = Droppable::new();
+        c(|: a: int, b| { z; zz; a + b });
+        assert_eq!(drop_count(), 9);
+    }
+    assert_eq!(drop_count(), 9);
+}
+
+fn main() {
+    test_fn();
+    test_fn_mut();
+    test_fn_once();
+}
+
diff --git a/src/test/run-pass/unboxed-closures-single-word-env.rs b/src/test/run-pass/unboxed-closures-single-word-env.rs
new file mode 100644
index 00000000000..754b1f70644
--- /dev/null
+++ b/src/test/run-pass/unboxed-closures-single-word-env.rs
@@ -0,0 +1,34 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Ensures that single-word environments work right in unboxed closures.
+// These take a different path in codegen.
+
+#![feature(overloaded_calls, unboxed_closures)]
+
+fn a<F:|&: int, int| -> int>(f: F) -> int {
+    f(1, 2)
+}
+
+fn b<F:|&mut: int, int| -> int>(mut f: F) -> int {
+    f(3, 4)
+}
+
+fn c<F:|: int, int| -> int>(f: F) -> int {
+    f(5, 6)
+}
+
+fn main() {
+    let z = 10;
+    assert_eq!(a(|&: x: int, y| x + y + z), 13);
+    assert_eq!(b(|&mut: x: int, y| x + y + z), 17);
+    assert_eq!(c(|: x: int, y| x + y + z), 21);
+}
+