about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAman Arora <me@aman-arora.com>2020-11-25 15:15:55 -0500
committerAman Arora <me@aman-arora.com>2020-12-11 05:19:16 -0500
commit01df56343bf1884d5e1d82e813e2930c6d9d5dd6 (patch)
tree0352c24d3de6f52e081544df6bbf6fce484ebf8e
parent237ad1269844f483eb708de015b950253d906886 (diff)
downloadrust-01df56343bf1884d5e1d82e813e2930c6d9d5dd6.tar.gz
rust-01df56343bf1884d5e1d82e813e2930c6d9d5dd6.zip
Test cases for RFC 2229
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.rs86
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr111
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/box.rs65
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr55
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.rs28
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr26
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.rs26
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr26
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/box.rs97
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/box.stderr11
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.rs28
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.stderr11
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.rs23
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.stderr11
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.rs24
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.stderr11
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.rs27
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.stderr11
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.rs41
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.stderr11
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.rs36
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.stderr11
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.rs34
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.stderr11
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.rs31
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.stderr11
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.rs40
-rw-r--r--src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.stderr11
28 files changed, 914 insertions, 0 deletions
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.rs
new file mode 100644
index 00000000000..0b94317fd71
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.rs
@@ -0,0 +1,86 @@
+// Test that arrays are completely captured by closures by relying on the borrow check diagnostics
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+fn arrays_1() {
+    let mut arr = [1, 2, 3, 4, 5];
+
+    let mut c = || {
+        arr[0] += 10;
+    };
+
+    // c will capture `arr` completely, therefore another index into the
+    // array can't be modified here
+    arr[1] += 10;
+    //~^ ERROR: cannot use `arr` because it was mutably borrowed
+    //~| ERROR: cannot use `arr[_]` because it was mutably borrowed
+    c();
+}
+
+fn arrays_2() {
+    let mut arr = [1, 2, 3, 4, 5];
+
+    let c = || {
+        println!("{:#?}", &arr[3..4]);
+    };
+
+    // c will capture `arr` completely, therefore another index into the
+    // array can't be modified here
+    arr[1] += 10;
+    //~^ ERROR: cannot assign to `arr[_]` because it is borrowed
+    c();
+}
+
+fn arrays_3() {
+    let mut arr = [1, 2, 3, 4, 5];
+
+    let c = || {
+        println!("{}", arr[3]);
+    };
+
+    // c will capture `arr` completely, therefore another index into the
+    // array can't be modified here
+    arr[1] += 10;
+    //~^ ERROR: cannot assign to `arr[_]` because it is borrowed
+    c();
+}
+
+fn arrays_4() {
+    let mut arr = [1, 2, 3, 4, 5];
+
+    let mut c = || {
+        arr[1] += 10;
+    };
+
+    // c will capture `arr` completely, therefore we cannot borrow another index
+    // into the array.
+    println!("{}", arr[3]);
+    //~^ ERROR: cannot use `arr` because it was mutably borrowed
+    //~| ERROR: cannot borrow `arr[_]` as immutable because it is also borrowed as mutable
+
+    c();
+}
+
+fn arrays_5() {
+    let mut arr = [1, 2, 3, 4, 5];
+
+    let mut c = || {
+        arr[1] += 10;
+    };
+
+    // c will capture `arr` completely, therefore we cannot borrow other indecies
+    // into the array.
+    println!("{:#?}", &arr[3..2]);
+    //~^ ERROR: cannot borrow `arr` as immutable because it is also borrowed as mutable
+
+    c();
+}
+
+fn main() {
+    arrays_1();
+    arrays_2();
+    arrays_3();
+    arrays_4();
+    arrays_5();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr
new file mode 100644
index 00000000000..77e3e71bc61
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr
@@ -0,0 +1,111 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/arrays.rs:3:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0503]: cannot use `arr` because it was mutably borrowed
+  --> $DIR/arrays.rs:15:5
+   |
+LL |     let mut c = || {
+   |                 -- borrow of `arr` occurs here
+LL |         arr[0] += 10;
+   |         --- borrow occurs due to use of `arr` in closure
+...
+LL |     arr[1] += 10;
+   |     ^^^^^^ use of borrowed `arr`
+...
+LL |     c();
+   |     - borrow later used here
+
+error[E0503]: cannot use `arr[_]` because it was mutably borrowed
+  --> $DIR/arrays.rs:15:5
+   |
+LL |     let mut c = || {
+   |                 -- borrow of `arr` occurs here
+LL |         arr[0] += 10;
+   |         --- borrow occurs due to use of `arr` in closure
+...
+LL |     arr[1] += 10;
+   |     ^^^^^^^^^^^^ use of borrowed `arr`
+...
+LL |     c();
+   |     - borrow later used here
+
+error[E0506]: cannot assign to `arr[_]` because it is borrowed
+  --> $DIR/arrays.rs:30:5
+   |
+LL |     let c = || {
+   |             -- borrow of `arr[_]` occurs here
+LL |         println!("{:#?}", &arr[3..4]);
+   |                            --- borrow occurs due to use in closure
+...
+LL |     arr[1] += 10;
+   |     ^^^^^^^^^^^^ assignment to borrowed `arr[_]` occurs here
+LL |
+LL |     c();
+   |     - borrow later used here
+
+error[E0506]: cannot assign to `arr[_]` because it is borrowed
+  --> $DIR/arrays.rs:44:5
+   |
+LL |     let c = || {
+   |             -- borrow of `arr[_]` occurs here
+LL |         println!("{}", arr[3]);
+   |                        --- borrow occurs due to use in closure
+...
+LL |     arr[1] += 10;
+   |     ^^^^^^^^^^^^ assignment to borrowed `arr[_]` occurs here
+LL |
+LL |     c();
+   |     - borrow later used here
+
+error[E0503]: cannot use `arr` because it was mutably borrowed
+  --> $DIR/arrays.rs:58:20
+   |
+LL |     let mut c = || {
+   |                 -- borrow of `arr` occurs here
+LL |         arr[1] += 10;
+   |         --- borrow occurs due to use of `arr` in closure
+...
+LL |     println!("{}", arr[3]);
+   |                    ^^^^^^ use of borrowed `arr`
+...
+LL |     c();
+   |     - borrow later used here
+
+error[E0502]: cannot borrow `arr[_]` as immutable because it is also borrowed as mutable
+  --> $DIR/arrays.rs:58:20
+   |
+LL |     let mut c = || {
+   |                 -- mutable borrow occurs here
+LL |         arr[1] += 10;
+   |         --- first borrow occurs due to use of `arr` in closure
+...
+LL |     println!("{}", arr[3]);
+   |                    ^^^^^^ immutable borrow occurs here
+...
+LL |     c();
+   |     - mutable borrow later used here
+
+error[E0502]: cannot borrow `arr` as immutable because it is also borrowed as mutable
+  --> $DIR/arrays.rs:74:24
+   |
+LL |     let mut c = || {
+   |                 -- mutable borrow occurs here
+LL |         arr[1] += 10;
+   |         --- first borrow occurs due to use of `arr` in closure
+...
+LL |     println!("{:#?}", &arr[3..2]);
+   |                        ^^^ immutable borrow occurs here
+...
+LL |     c();
+   |     - mutable borrow later used here
+
+error: aborting due to 7 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0502, E0503, E0506.
+For more information about an error, try `rustc --explain E0502`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/box.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.rs
new file mode 100644
index 00000000000..15be1d8c722
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.rs
@@ -0,0 +1,65 @@
+// Test borrow checker when we precise capture when using boxes
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+struct MetaData { x: String, name: String }
+struct Data { m: MetaData }
+struct BoxedData(Box<Data>);
+struct EvenMoreBoxedData(Box<BoxedData>);
+
+// Check diagnostics when the same path is mutated both inside and outside the closure
+fn box_1() {
+    let m = MetaData { x: format!("x"), name: format!("name") };
+    let d = Data { m };
+    let b = BoxedData(Box::new(d));
+    let mut e = EvenMoreBoxedData(Box::new(b));
+
+    let mut c = || {
+        e.0.0.m.x = format!("not-x");
+    };
+
+    e.0.0.m.x = format!("not-x");
+    //~^ ERROR: cannot assign to `e.0.0.m.x` because it is borrowed
+    c();
+}
+
+// Check diagnostics when a path is mutated inside a closure while attempting to read it outside
+// the closure.
+fn box_2() {
+    let m = MetaData { x: format!("x"), name: format!("name") };
+    let d = Data { m };
+    let b = BoxedData(Box::new(d));
+    let mut e = EvenMoreBoxedData(Box::new(b));
+
+    let mut c = || {
+        e.0.0.m.x = format!("not-x");
+    };
+
+    println!("{}", e.0.0.m.x);
+    //~^ ERROR: cannot borrow `e.0.0.m.x` as immutable because it is also borrowed as mutable
+    c();
+}
+
+// Check diagnostics when a path is read inside a closure while attempting to mutate it outside
+// the closure.
+fn box_3() {
+    let m = MetaData { x: format!("x"), name: format!("name") };
+    let d = Data { m };
+    let b = BoxedData(Box::new(d));
+    let mut e = EvenMoreBoxedData(Box::new(b));
+
+    let c = || {
+        println!("{}", e.0.0.m.x);
+    };
+
+    e.0.0.m.x = format!("not-x");
+    //~^ ERROR: cannot assign to `e.0.0.m.x` because it is borrowed
+    c();
+}
+
+fn main() {
+    box_1();
+    box_2();
+    box_3();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr
new file mode 100644
index 00000000000..17a9332fb3e
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr
@@ -0,0 +1,55 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/box.rs:3:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed
+  --> $DIR/box.rs:22:5
+   |
+LL |     let mut c = || {
+   |                 -- borrow of `e.0.0.m.x` occurs here
+LL |         e.0.0.m.x = format!("not-x");
+   |         - borrow occurs due to use in closure
+...
+LL |     e.0.0.m.x = format!("not-x");
+   |     ^^^^^^^^^ assignment to borrowed `e.0.0.m.x` occurs here
+LL |
+LL |     c();
+   |     - borrow later used here
+
+error[E0502]: cannot borrow `e.0.0.m.x` as immutable because it is also borrowed as mutable
+  --> $DIR/box.rs:39:20
+   |
+LL |     let mut c = || {
+   |                 -- mutable borrow occurs here
+LL |         e.0.0.m.x = format!("not-x");
+   |         - first borrow occurs due to use of `e.0.0.m.x` in closure
+...
+LL |     println!("{}", e.0.0.m.x);
+   |                    ^^^^^^^^^ immutable borrow occurs here
+LL |
+LL |     c();
+   |     - mutable borrow later used here
+
+error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed
+  --> $DIR/box.rs:56:5
+   |
+LL |     let c = || {
+   |             -- borrow of `e.0.0.m.x` occurs here
+LL |         println!("{}", e.0.0.m.x);
+   |                        - borrow occurs due to use in closure
+...
+LL |     e.0.0.m.x = format!("not-x");
+   |     ^^^^^^^^^ assignment to borrowed `e.0.0.m.x` occurs here
+LL |
+LL |     c();
+   |     - borrow later used here
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0502, E0506.
+For more information about an error, try `rustc --explain E0502`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.rs
new file mode 100644
index 00000000000..39b04c833e3
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.rs
@@ -0,0 +1,28 @@
+// Test that when a borrow checker diagnostics are emitted, it's as precise
+// as the capture by the closure.
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+#![allow(unused)]
+
+struct Point {
+    x: i32,
+    y: i32,
+}
+struct Wrapper {
+    p: Point,
+}
+
+fn main() {
+    let mut w = Wrapper { p: Point { x: 10, y: 10 } };
+
+    let mut c = || {
+        w.p.x += 20;
+    };
+
+    let py = &mut w.p.x;
+    //~^ ERROR: cannot borrow `w.p.x` as mutable more than once at a time
+    c();
+
+    *py = 20
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr
new file mode 100644
index 00000000000..e5a396c4e98
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr
@@ -0,0 +1,26 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/multilevel-path.rs:4:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0499]: cannot borrow `w.p.x` as mutable more than once at a time
+  --> $DIR/multilevel-path.rs:23:14
+   |
+LL |     let mut c = || {
+   |                 -- first mutable borrow occurs here
+LL |         w.p.x += 20;
+   |         - first borrow occurs due to use of `w.p.x` in closure
+...
+LL |     let py = &mut w.p.x;
+   |              ^^^^^^^^^^ second mutable borrow occurs here
+LL |
+LL |     c();
+   |     - first borrow later used here
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.rs
new file mode 100644
index 00000000000..e78d8715e48
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.rs
@@ -0,0 +1,26 @@
+// Test that borrow checker error is accurate and that min capture pass of the
+// closure analysis is working as expected.
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+#[derive(Debug)]
+struct Point {
+    x: i32,
+    y: i32,
+}
+
+fn main() {
+    let mut p = Point { x: 10, y: 20 };
+
+    // `p` is captured via mutable borrow.
+    let mut c = || {
+        p.x += 10;
+        println!("{:?}", p);
+    };
+
+
+    println!("{:?}", p);
+    //~^ ERROR: cannot borrow `p` as immutable because it is also borrowed as mutable
+    c();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr
new file mode 100644
index 00000000000..45a61cd98b1
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr
@@ -0,0 +1,26 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/simple-struct-min-capture.rs:4:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable
+  --> $DIR/simple-struct-min-capture.rs:23:22
+   |
+LL |     let mut c = || {
+   |                 -- mutable borrow occurs here
+LL |         p.x += 10;
+   |         - first borrow occurs due to use of `p` in closure
+...
+LL |     println!("{:?}", p);
+   |                      ^ immutable borrow occurs here
+LL |
+LL |     c();
+   |     - mutable borrow later used here
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/box.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/box.rs
new file mode 100644
index 00000000000..3a66399d028
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/box.rs
@@ -0,0 +1,97 @@
+// run-pass
+
+// Test precise capture when using boxes
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| NOTE: `#[warn(incomplete_features)]` on by default
+//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+
+
+struct MetaData { x: String, name: String }
+struct Data { m: MetaData }
+struct BoxedData(Box<Data>);
+struct EvenMoreBoxedData(Box<BoxedData>);
+
+// Mutate disjoint paths, one inside one outside the closure
+fn box_1() {
+    let m = MetaData { x: format!("x"), name: format!("name") };
+    let d = Data { m };
+    let b = BoxedData(Box::new(d));
+    let mut e = EvenMoreBoxedData(Box::new(b));
+
+    let mut c = || {
+        e.0.0.m.x = format!("not-x");
+    };
+
+    e.0.0.m.name = format!("not-name");
+    c();
+}
+
+// Mutate a path inside the closure and read a disjoint path outside the closure
+fn box_2() {
+    let m = MetaData { x: format!("x"), name: format!("name") };
+    let d = Data { m };
+    let b = BoxedData(Box::new(d));
+    let mut e = EvenMoreBoxedData(Box::new(b));
+
+    let mut c = || {
+        e.0.0.m.x = format!("not-x");
+    };
+
+    println!("{}", e.0.0.m.name);
+    c();
+}
+
+// Read a path inside the closure and mutate a disjoint path outside the closure
+fn box_3() {
+    let m = MetaData { x: format!("x"), name: format!("name") };
+    let d = Data { m };
+    let b = BoxedData(Box::new(d));
+    let mut e = EvenMoreBoxedData(Box::new(b));
+
+    let c = || {
+        println!("{}", e.0.0.m.name);
+    };
+
+    e.0.0.m.x = format!("not-x");
+    c();
+}
+
+// Read disjoint paths, one inside the closure and one outside the closure.
+fn box_4() {
+    let m = MetaData { x: format!("x"), name: format!("name") };
+    let d = Data { m };
+    let b = BoxedData(Box::new(d));
+    let e = EvenMoreBoxedData(Box::new(b));
+
+    let c = || {
+        println!("{}", e.0.0.m.name);
+    };
+
+    println!("{}", e.0.0.m.x);
+    c();
+}
+
+// Read the same path, once inside the closure and once outside the closure.
+fn box_5() {
+    let m = MetaData { x: format!("x"), name: format!("name") };
+    let d = Data { m };
+    let b = BoxedData(Box::new(d));
+    let e = EvenMoreBoxedData(Box::new(b));
+
+    let c = || {
+        println!("{}", e.0.0.m.name);
+    };
+
+    println!("{}", e.0.0.m.name);
+    c();
+}
+
+fn main() {
+    box_1();
+    box_2();
+    box_3();
+    box_4();
+    box_5();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/box.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/box.stderr
new file mode 100644
index 00000000000..9883c01b946
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/box.stderr
@@ -0,0 +1,11 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/box.rs:5:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.rs
new file mode 100644
index 00000000000..2c359519b76
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.rs
@@ -0,0 +1,28 @@
+// run-pass
+
+// Test that we can immutably borrow field of an instance of a structure from within a closure,
+// while having a mutable borrow to another field of the same instance outside the closure.
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| NOTE: `#[warn(incomplete_features)]` on by default
+//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+
+struct Point {
+    x: i32,
+    y: i32,
+}
+
+fn main() {
+    let mut p = Point { x: 10, y: 10 };
+
+    let c = || {
+        println!("{}", p.x);
+    };
+
+    // `c` should only capture `p.x`, therefore mutating `p.y` is allowed.
+    let py = &mut p.y;
+
+    c();
+    *py = 20;
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.stderr
new file mode 100644
index 00000000000..9b0dea770fb
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.stderr
@@ -0,0 +1,11 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/capture-disjoint-field-struct.rs:6:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.rs
new file mode 100644
index 00000000000..2c6679feabe
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.rs
@@ -0,0 +1,23 @@
+// run-pass
+
+// Test that we can mutate an element of a tuple from within a closure
+// while immutably borrowing another element of the same tuple outside the closure.
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| NOTE: `#[warn(incomplete_features)]` on by default
+//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+#![feature(rustc_attrs)]
+
+fn main() {
+    let mut t = (10, 10);
+
+    let mut c = || {
+        let t1 = &mut t.1;
+        *t1 = 20;
+    };
+
+    // Test that `c` only captures t.1, therefore reading t.0 is allowed.
+    println!("{}", t.0);
+    c();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.stderr
new file mode 100644
index 00000000000..28d09153952
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.stderr
@@ -0,0 +1,11 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/capture-disjoint-field-tuple-mut.rs:6:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.rs
new file mode 100644
index 00000000000..52f5cef9f01
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.rs
@@ -0,0 +1,24 @@
+// run-pass
+
+// Test that we can immutably borrow an element of a tuple from within a closure,
+// while having a mutable borrow to another element of the same tuple outside the closure.
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| NOTE: `#[warn(incomplete_features)]` on by default
+//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+#![feature(rustc_attrs)]
+
+fn main() {
+    let mut t = (10, 10);
+
+    let c = || {
+        println!("{}", t.0);
+    };
+
+    // `c` only captures t.0, therefore mutating t.1 is allowed.
+    let t1 = &mut t.1;
+
+    c();
+    *t1 = 20;
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.stderr
new file mode 100644
index 00000000000..4fb37f85f88
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.stderr
@@ -0,0 +1,11 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/capture-disjoint-field-tuple.rs:6:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.rs
new file mode 100644
index 00000000000..3f8e197b783
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.rs
@@ -0,0 +1,27 @@
+// run-pass
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| NOTE: `#[warn(incomplete_features)]` on by default
+//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+
+// Tests that if a closure uses indivual fields of the same object
+// then that case is handled properly.
+
+#![allow(unused)]
+
+struct Struct {
+    x: i32,
+    y: i32,
+    s: String,
+}
+
+fn main() {
+    let mut s = Struct { x: 10, y: 10, s: String::new() };
+
+    let mut c = {
+        s.x += 10;
+        s.y += 42;
+        s.s = String::from("new");
+    };
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.stderr
new file mode 100644
index 00000000000..bba90f8917a
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.stderr
@@ -0,0 +1,11 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/disjoint-capture-in-same-closure.rs:3:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.rs
new file mode 100644
index 00000000000..8c12593430e
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.rs
@@ -0,0 +1,41 @@
+// run-pass
+
+// Test disjoint capture within an impl block
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| NOTE: `#[warn(incomplete_features)]` on by default
+//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+
+struct Filter {
+    div: i32,
+}
+impl Filter {
+    fn allowed(&self, x: i32) -> bool {
+        x % self.div == 1
+    }
+}
+
+struct Data {
+    filter: Filter,
+    list: Vec<i32>,
+}
+impl Data {
+    fn update(&mut self) {
+        // The closure passed to filter only captures self.filter,
+        // therefore mutating self.list is allowed.
+        self.list.retain(
+            |v| self.filter.allowed(*v),
+        );
+    }
+}
+
+fn main() {
+    let mut d = Data { filter: Filter { div: 3 }, list: Vec::new() };
+
+    for i in 1..10 {
+        d.list.push(i);
+    }
+
+    d.update();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.stderr
new file mode 100644
index 00000000000..6930e18992a
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.stderr
@@ -0,0 +1,11 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/filter-on-struct-member.rs:5:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.rs
new file mode 100644
index 00000000000..142c156bd56
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.rs
@@ -0,0 +1,36 @@
+// run-pass
+
+// Test that closures can catpure paths that are more precise than just one level
+// from the root variable.
+//
+// If the closures can handle such precison we should be able to mutate one path in the closure
+// while being able to mutate another path outside the closure, where the two paths are disjoint
+// after applying two projections on the root variable.
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| NOTE: `#[warn(incomplete_features)]` on by default
+//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+#![allow(unused)]
+
+struct Point {
+    x: i32,
+    y: i32,
+}
+struct Wrapper {
+    p: Point,
+}
+
+fn main() {
+    let mut w = Wrapper { p: Point { x: 10, y: 10 } };
+
+    let mut c = || {
+        w.p.x += 20;
+    };
+
+    // `c` only captures `w.p.x`, therefore it's safe to mutate `w.p.y`.
+    let py = &mut w.p.y;
+    c();
+
+    *py = 20
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.stderr
new file mode 100644
index 00000000000..94b877522f4
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.stderr
@@ -0,0 +1,11 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/multilevel-path-1.rs:10:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.rs
new file mode 100644
index 00000000000..d8f7d55d5aa
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.rs
@@ -0,0 +1,34 @@
+// run-pass
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| NOTE: `#[warn(incomplete_features)]` on by default
+//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+#![allow(unused)]
+
+// If the closures can handle such precison we should be able to read one path in the closure
+// while being able mutate another path outside the closure, where the two paths are disjoint
+// after applying two projections on the root variable.
+
+
+struct Point {
+    x: i32,
+    y: i32,
+}
+struct Wrapper {
+    p: Point,
+}
+
+fn main() {
+    let mut w = Wrapper { p: Point { x: 10, y: 10 } };
+
+    let c = || {
+        println!("{}", w.p.x);
+    };
+
+    // `c` only captures `w.p.x`, therefore it's safe to mutate `w.p.y`.
+    let py = &mut w.p.y;
+    c();
+
+    *py = 20
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.stderr
new file mode 100644
index 00000000000..100a0e167c5
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.stderr
@@ -0,0 +1,11 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/multilevel-path-2.rs:3:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.rs
new file mode 100644
index 00000000000..fc3d48ec458
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.rs
@@ -0,0 +1,31 @@
+// run-pass
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| NOTE: `#[warn(incomplete_features)]` on by default
+//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+#![allow(unused)]
+
+// Test that when `capture_disjoint_fields` is enabled we can read a path
+// both inside and outside the closure at the same time.
+
+struct Point {
+    x: i32,
+    y: i32,
+}
+struct Wrapper {
+    p: Point,
+}
+
+fn main() {
+    let mut w = Wrapper { p: Point { x: 10, y: 10 } };
+
+    let c = || {
+        println!("{}", w.p.x);
+    };
+
+    let px = &w.p.x;
+    c();
+
+    println!("{}", px);
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.stderr
new file mode 100644
index 00000000000..cf5be6a00e9
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.stderr
@@ -0,0 +1,11 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/multilevel-path-3.rs:3:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.rs
new file mode 100644
index 00000000000..238580929ef
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.rs
@@ -0,0 +1,40 @@
+// run-pass
+
+// Test whether if we can do precise capture when using nested clsoure.
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| NOTE: `#[warn(incomplete_features)]` on by default
+//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+
+struct Point {
+    x: i32,
+    y: i32,
+}
+
+fn main() {
+    let mut p = Point { x: 5, y: 20 };
+
+    // c1 should capture `p.x` via immutable borrow and
+    // `p.y` via mutable borrow.
+    let mut c1 = || {
+        println!("{}", p.x);
+
+        let incr = 10;
+
+        let mut c2 = || p.y += incr;
+        c2();
+
+        println!("{}", p.y);
+    };
+
+    c1();
+
+    // This should not throw an error because `p.x` is borrowed via Immutable borrow,
+    // and multiple immutable borrow of the same place are allowed.
+    let px = &p.x;
+
+    println!("{}", px);
+
+    c1();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.stderr
new file mode 100644
index 00000000000..293aa82ce9f
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/run_pass/nested-closure.stderr
@@ -0,0 +1,11 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/nested-closure.rs:5:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+warning: 1 warning emitted
+