summaryrefslogtreecommitdiffstats
path: root/src/test/ui/closures/2229_closure_analysis/diagnostics
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/ui/closures/2229_closure_analysis/diagnostics')
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.rs85
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr104
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.rs19
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr19
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs19
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr19
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs18
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr18
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs20
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr22
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs26
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr21
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/box.rs64
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr48
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.rs19
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr12
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs34
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr21
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.rs13
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.stderr14
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-multi-variant-diagnostics.rs27
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-multi-variant-diagnostics.stderr21
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.rs18
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr21
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-struct-diagnostics.rs22
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-struct-diagnostics.stderr21
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics-1.rs13
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics-1.stderr21
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.rs13
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.stderr14
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.rs92
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.stderr65
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.rs43
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.stderr33
-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.stderr17
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.rs37
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr24
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.rs32
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr29
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.rs25
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr21
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/union.rs25
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/union.stderr18
44 files changed, 1295 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 000000000..93131b2ac
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.rs
@@ -0,0 +1,85 @@
+// edition:2021
+
+// Test that arrays are completely captured by closures by relying on the borrow check diagnostics
+
+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 000000000..4f41060dc
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr
@@ -0,0 +1,104 @@
+error[E0503]: cannot use `arr` because it was mutably borrowed
+ --> $DIR/arrays.rs:14: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:14: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:29: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:43: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:57: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:57: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
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0502]: cannot borrow `arr` as immutable because it is also borrowed as mutable
+ --> $DIR/arrays.rs:73: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
+
+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/borrowck/borrowck-1.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.rs
new file mode 100644
index 000000000..3664d76c2
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.rs
@@ -0,0 +1,19 @@
+// edition:2021
+
+#[derive(Debug)]
+struct Point {
+ x: i32,
+ y: i32,
+}
+fn main() {
+ let mut p = Point {x: 1, y: 2 };
+
+ let y = &mut p.y;
+ let mut c = || {
+ //~^ ERROR cannot borrow `p` as mutable more than once at a time
+ let x = &mut p.x;
+ println!("{:?}", p);
+ };
+ c();
+ *y+=1;
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr
new file mode 100644
index 000000000..341d2bc65
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr
@@ -0,0 +1,19 @@
+error[E0499]: cannot borrow `p` as mutable more than once at a time
+ --> $DIR/borrowck-1.rs:12:17
+ |
+LL | let y = &mut p.y;
+ | -------- first mutable borrow occurs here
+LL | let mut c = || {
+ | ^^ second mutable borrow occurs here
+LL |
+LL | let x = &mut p.x;
+ | --- capture is mutable because of use here
+LL | println!("{:?}", p);
+ | - second borrow occurs due to use of `p` in closure
+...
+LL | *y+=1;
+ | ----- first borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs
new file mode 100644
index 000000000..ae416bab6
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs
@@ -0,0 +1,19 @@
+// edition:2021
+
+#[derive(Debug)]
+struct Point {
+ x: i32,
+ y: i32,
+}
+fn main() {
+ let mut p = Point {x: 1, y: 2 };
+
+ let y = &p.y;
+ let mut c = || {
+ //~^ ERROR cannot borrow `p` as mutable because it is also borrowed as immutable
+ println!("{:?}", p);
+ let x = &mut p.x;
+ };
+ c();
+ println!("{}", y);
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr
new file mode 100644
index 000000000..584bb862b
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr
@@ -0,0 +1,19 @@
+error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-2.rs:12:17
+ |
+LL | let y = &p.y;
+ | ---- immutable borrow occurs here
+LL | let mut c = || {
+ | ^^ mutable borrow occurs here
+LL |
+LL | println!("{:?}", p);
+ | - second borrow occurs due to use of `p` in closure
+LL | let x = &mut p.x;
+ | --- capture is mutable because of use here
+...
+LL | println!("{}", y);
+ | - immutable borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs
new file mode 100644
index 000000000..bdd6cb79b
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs
@@ -0,0 +1,18 @@
+// edition:2021
+
+#[derive(Debug)]
+struct Point {
+ x: String,
+ y: String,
+}
+fn main() {
+ let mut c = {
+ let mut p = Point {x: "1".to_string(), y: "2".to_string() };
+ || {
+ let x = &mut p.x;
+ println!("{:?}", p);
+ //~^ ERROR `p` does not live long enough
+ }
+ };
+ c();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr
new file mode 100644
index 000000000..dab1809a3
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr
@@ -0,0 +1,18 @@
+error[E0597]: `p` does not live long enough
+ --> $DIR/borrowck-3.rs:13:29
+ |
+LL | let mut c = {
+ | ----- borrow later stored here
+LL | let mut p = Point {x: "1".to_string(), y: "2".to_string() };
+LL | || {
+ | -- value captured here
+LL | let x = &mut p.x;
+LL | println!("{:?}", p);
+ | ^ borrowed value does not live long enough
+...
+LL | };
+ | - `p` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs
new file mode 100644
index 000000000..a2290d850
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs
@@ -0,0 +1,20 @@
+// edition:2021
+
+#[derive(Debug)]
+struct Point {
+ x: i32,
+ y: i32,
+}
+fn foo () -> impl FnMut()->() {
+ let mut p = Point {x: 1, y: 2 };
+ let mut c = || {
+ //~^ ERROR closure may outlive the current function, but it borrows `p`
+ p.x+=5;
+ println!("{:?}", p);
+ };
+ c
+}
+fn main() {
+ let c = foo();
+ c();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr
new file mode 100644
index 000000000..46379a381
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr
@@ -0,0 +1,22 @@
+error[E0373]: closure may outlive the current function, but it borrows `p`, which is owned by the current function
+ --> $DIR/borrowck-4.rs:10:17
+ |
+LL | let mut c = || {
+ | ^^ may outlive borrowed value `p`
+...
+LL | println!("{:?}", p);
+ | - `p` is borrowed here
+ |
+note: closure is returned here
+ --> $DIR/borrowck-4.rs:15:5
+ |
+LL | c
+ | ^
+help: to force the closure to take ownership of `p` (and any other referenced variables), use the `move` keyword
+ |
+LL | let mut c = move || {
+ | ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0373`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs
new file mode 100644
index 000000000..5ff7b1242
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs
@@ -0,0 +1,26 @@
+// edition:2021
+
+
+
+// Tests that two closures cannot simultaneously have mutable
+// and immutable access to the variable. Issue #6801.
+
+#[derive(Debug)]
+struct Point {
+ x: i32,
+ y: i32,
+}
+
+fn a() {
+ let mut p = Point {x: 3, y:4};
+ let c2 = || p.y * 5;
+ let c1 = || {
+ //~^ ERROR cannot borrow `p` as mutable because it is also borrowed as immutable
+ dbg!(&p);
+ p.x = 4;
+ };
+ drop(c2);
+}
+
+fn main() {
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr
new file mode 100644
index 000000000..5f1dae297
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr
@@ -0,0 +1,21 @@
+error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-closures-mut-and-imm.rs:17:14
+ |
+LL | let c2 = || p.y * 5;
+ | -- --- first borrow occurs due to use of `p.y` in closure
+ | |
+ | immutable borrow occurs here
+LL | let c1 = || {
+ | ^^ mutable borrow occurs here
+LL |
+LL | dbg!(&p);
+ | - second borrow occurs due to use of `p` in closure
+LL | p.x = 4;
+ | --- capture is mutable because of use here
+LL | };
+LL | drop(c2);
+ | -- immutable borrow later used here
+
+error: aborting due to previous error
+
+For more information about this 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 000000000..a110fa4e2
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.rs
@@ -0,0 +1,64 @@
+// edition:2021
+
+// Test borrow checker when we precise capture when using boxes
+
+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 000000000..f8b178752
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr
@@ -0,0 +1,48 @@
+error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed
+ --> $DIR/box.rs:21: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:38: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
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed
+ --> $DIR/box.rs:55: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
+
+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/cant-mutate-imm-borrow.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.rs
new file mode 100644
index 000000000..77effcb00
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.rs
@@ -0,0 +1,19 @@
+// edition:2021
+
+// Test that if we deref an immutable borrow to access a Place,
+// then we can't mutate the final place.
+
+fn main() {
+ let mut x = (format!(""), format!("X2"));
+ let mut y = (&x, "Y");
+ let z = (&mut y, "Z");
+
+ // `x.0` is mutable but we access `x` via `*z.0.0`, which is an immutable reference and
+ // therefore can't be mutated.
+ let mut c = || {
+ //~^ ERROR: cannot borrow `*z.0.0` as mutable, as it is behind a `&` reference
+ z.0.0.0 = format!("X1");
+ };
+
+ c();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr
new file mode 100644
index 000000000..38c530b80
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr
@@ -0,0 +1,12 @@
+error[E0596]: cannot borrow `*z.0.0` as mutable, as it is behind a `&` reference
+ --> $DIR/cant-mutate-imm-borrow.rs:13:17
+ |
+LL | let mut c = || {
+ | ^^ cannot borrow as mutable
+LL |
+LL | z.0.0.0 = format!("X1");
+ | ------- mutable borrow occurs due to use of `*z.0.0` in closure
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs
new file mode 100644
index 000000000..25ee9a149
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs
@@ -0,0 +1,34 @@
+// edition:2021
+
+// Ensure that diagnostics for mutability error (because the root variable
+// isn't mutable) work with `capture_disjoint_fields` enabled.
+
+fn mut_error_struct() {
+ let x = (10, 10);
+ let y = (x, 10);
+ let z = (y, 10);
+
+ let mut c = || {
+ z.0.0.0 = 20;
+ //~^ ERROR: cannot assign to `z.0.0.0`, as it is not declared as mutable
+ };
+
+ c();
+}
+
+fn mut_error_box() {
+ let x = (10, 10);
+ let bx = Box::new(x);
+
+ let mut c = || {
+ bx.0 = 20;
+ //~^ ERROR: cannot assign to `*bx.0`, as it is not declared as mutable
+ };
+
+ c();
+}
+
+fn main() {
+ mut_error_struct();
+ mut_error_box();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr
new file mode 100644
index 000000000..98414fa8a
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr
@@ -0,0 +1,21 @@
+error[E0594]: cannot assign to `z.0.0.0`, as it is not declared as mutable
+ --> $DIR/cant-mutate-imm.rs:12:9
+ |
+LL | let z = (y, 10);
+ | - help: consider changing this to be mutable: `mut z`
+...
+LL | z.0.0.0 = 20;
+ | ^^^^^^^^^^^^ cannot assign
+
+error[E0594]: cannot assign to `*bx.0`, as it is not declared as mutable
+ --> $DIR/cant-mutate-imm.rs:24:9
+ |
+LL | let bx = Box::new(x);
+ | -- help: consider changing this to be mutable: `mut bx`
+...
+LL | bx.0 = 20;
+ | ^^^^^^^^^ cannot assign
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.rs
new file mode 100644
index 000000000..f3be542e4
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.rs
@@ -0,0 +1,13 @@
+// edition:2021
+
+// Test that array access is not stored as part of closure kind origin
+
+fn expect_fn<F: Fn()>(_f: F) {}
+
+fn main() {
+ let s = [format!("s"), format!("s")];
+ let c = || { //~ ERROR expected a closure that implements the `Fn`
+ let [_, _s] = s;
+ };
+ expect_fn(c);
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.stderr
new file mode 100644
index 000000000..bcde35983
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-array-diagnostics.stderr
@@ -0,0 +1,14 @@
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
+ --> $DIR/closure-origin-array-diagnostics.rs:9:13
+ |
+LL | let c = || {
+ | ^^ this closure implements `FnOnce`, not `Fn`
+LL | let [_, _s] = s;
+ | - closure is `FnOnce` because it moves the variable `s` out of its environment
+LL | };
+LL | expect_fn(c);
+ | --------- the requirement to implement `Fn` derives from here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0525`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-multi-variant-diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-multi-variant-diagnostics.rs
new file mode 100644
index 000000000..aa85b55b1
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-multi-variant-diagnostics.rs
@@ -0,0 +1,27 @@
+// edition:2021
+
+// Check that precise paths are being reported back in the error message.
+
+enum MultiVariant {
+ Point(i32, i32),
+ Meta(i32)
+}
+
+fn main() {
+ let mut point = MultiVariant::Point(10, -10,);
+
+ let mut meta = MultiVariant::Meta(1);
+
+ let c = || {
+ if let MultiVariant::Point(ref mut x, _) = point {
+ *x += 1;
+ }
+
+ if let MultiVariant::Meta(ref mut v) = meta {
+ *v += 1;
+ }
+ };
+
+ let a = c;
+ let b = c; //~ ERROR use of moved value: `c` [E0382]
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-multi-variant-diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-multi-variant-diagnostics.stderr
new file mode 100644
index 000000000..83d282aad
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-multi-variant-diagnostics.stderr
@@ -0,0 +1,21 @@
+error[E0382]: use of moved value: `c`
+ --> $DIR/closure-origin-multi-variant-diagnostics.rs:26:13
+ |
+LL | let a = c;
+ | - value moved here
+LL | let b = c;
+ | ^ value used here after move
+ |
+note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `point.0` out of its environment
+ --> $DIR/closure-origin-multi-variant-diagnostics.rs:16:52
+ |
+LL | if let MultiVariant::Point(ref mut x, _) = point {
+ | ^^^^^
+help: consider mutably borrowing `c`
+ |
+LL | let a = &mut c;
+ | ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.rs
new file mode 100644
index 000000000..bedb103cc
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.rs
@@ -0,0 +1,18 @@
+// edition:2021
+
+
+enum SingleVariant {
+ Point(i32, i32),
+}
+
+fn main() {
+ let mut point = SingleVariant::Point(10, -10);
+
+ let c = || {
+ let SingleVariant::Point(ref mut x, _) = point;
+ *x += 1;
+ };
+
+ let b = c;
+ let a = c; //~ ERROR use of moved value: `c` [E0382]
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr
new file mode 100644
index 000000000..46323b752
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr
@@ -0,0 +1,21 @@
+error[E0382]: use of moved value: `c`
+ --> $DIR/closure-origin-single-variant-diagnostics.rs:17:13
+ |
+LL | let b = c;
+ | - value moved here
+LL | let a = c;
+ | ^ value used here after move
+ |
+note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `point.0` out of its environment
+ --> $DIR/closure-origin-single-variant-diagnostics.rs:12:50
+ |
+LL | let SingleVariant::Point(ref mut x, _) = point;
+ | ^^^^^
+help: consider mutably borrowing `c`
+ |
+LL | let b = &mut c;
+ | ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-struct-diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-struct-diagnostics.rs
new file mode 100644
index 000000000..3277a83c4
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-struct-diagnostics.rs
@@ -0,0 +1,22 @@
+// edition:2021
+
+// Check that precise paths are being reported back in the error message.
+
+struct Y {
+ y: X
+}
+
+struct X {
+ a: u32,
+ b: u32,
+}
+
+fn main() {
+ let mut x = Y { y: X { a: 5, b: 0 } };
+ let hello = || {
+ x.y.a += 1;
+ };
+
+ let b = hello;
+ let c = hello; //~ ERROR use of moved value: `hello` [E0382]
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-struct-diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-struct-diagnostics.stderr
new file mode 100644
index 000000000..25029cc7b
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-struct-diagnostics.stderr
@@ -0,0 +1,21 @@
+error[E0382]: use of moved value: `hello`
+ --> $DIR/closure-origin-struct-diagnostics.rs:21:13
+ |
+LL | let b = hello;
+ | ----- value moved here
+LL | let c = hello;
+ | ^^^^^ value used here after move
+ |
+note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `x.y.a` out of its environment
+ --> $DIR/closure-origin-struct-diagnostics.rs:17:9
+ |
+LL | x.y.a += 1;
+ | ^^^^^
+help: consider mutably borrowing `hello`
+ |
+LL | let b = &mut hello;
+ | ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics-1.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics-1.rs
new file mode 100644
index 000000000..dc3a57ae7
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics-1.rs
@@ -0,0 +1,13 @@
+// edition:2021
+
+// Check that precise paths are being reported back in the error message.
+
+fn main() {
+ let mut x = (5, 0);
+ let hello = || {
+ x.0 += 1;
+ };
+
+ let b = hello;
+ let c = hello; //~ ERROR use of moved value: `hello` [E0382]
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics-1.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics-1.stderr
new file mode 100644
index 000000000..06ef7baf9
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics-1.stderr
@@ -0,0 +1,21 @@
+error[E0382]: use of moved value: `hello`
+ --> $DIR/closure-origin-tuple-diagnostics-1.rs:12:13
+ |
+LL | let b = hello;
+ | ----- value moved here
+LL | let c = hello;
+ | ^^^^^ value used here after move
+ |
+note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `x.0` out of its environment
+ --> $DIR/closure-origin-tuple-diagnostics-1.rs:8:9
+ |
+LL | x.0 += 1;
+ | ^^^
+help: consider mutably borrowing `hello`
+ |
+LL | let b = &mut hello;
+ | ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.rs
new file mode 100644
index 000000000..fa1328013
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.rs
@@ -0,0 +1,13 @@
+// edition:2021
+
+struct S(String, String);
+
+fn expect_fn<F: Fn()>(_f: F) {}
+
+fn main() {
+ let s = S(format!("s"), format!("s"));
+ let c = || { //~ ERROR expected a closure that implements the `Fn`
+ let s = s.1;
+ };
+ expect_fn(c);
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.stderr
new file mode 100644
index 000000000..df33c4f1f
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.stderr
@@ -0,0 +1,14 @@
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
+ --> $DIR/closure-origin-tuple-diagnostics.rs:9:13
+ |
+LL | let c = || {
+ | ^^ this closure implements `FnOnce`, not `Fn`
+LL | let s = s.1;
+ | --- closure is `FnOnce` because it moves the variable `s.1` out of its environment
+LL | };
+LL | expect_fn(c);
+ | --------- the requirement to implement `Fn` derives from here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0525`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.rs
new file mode 100644
index 000000000..3399bc001
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.rs
@@ -0,0 +1,92 @@
+// edition:2021
+
+// check-pass
+#![allow(unreachable_code)]
+#![warn(unused)]
+#![allow(dead_code)]
+
+#[derive(Debug)]
+struct Point {
+ x: i32,
+ y: i32,
+}
+
+pub fn f() {
+ let mut a = 1;
+ let mut c = Point{ x:1, y:0 };
+
+ // Captured by value, but variable is dead on entry.
+ (move || {
+ // This will not trigger a warning for unused variable as
+ // c.x will be treated as a Non-tracked place
+ c.x = 1;
+ println!("{}", c.x);
+ a = 1; //~ WARN value captured by `a` is never read
+ println!("{}", a);
+ })();
+
+ // Read and written to, but never actually used.
+ (move || {
+ // This will not trigger a warning for unused variable as
+ // c.x will be treated as a Non-tracked place
+ c.x += 1;
+ a += 1; //~ WARN unused variable: `a`
+ })();
+
+ (move || {
+ println!("{}", c.x);
+ // Value is read by closure itself on later invocations.
+ // This will not trigger a warning for unused variable as
+ // c.x will be treated as a Non-tracked place
+ c.x += 1;
+ println!("{}", a);
+ a += 1;
+ })();
+ let b = Box::new(42);
+ (move || {
+ println!("{}", c.x);
+ // Never read because this is FnOnce closure.
+ // This will not trigger a warning for unused variable as
+ // c.x will be treated as a Non-tracked place
+ c.x += 1;
+ println!("{}", a);
+ a += 1; //~ WARN value assigned to `a` is never read
+ drop(b);
+ })();
+}
+
+#[derive(Debug)]
+struct MyStruct<'a> {
+ x: Option<& 'a str>,
+ y: i32,
+}
+
+pub fn nested() {
+ let mut a : Option<& str>;
+ a = None;
+ let mut b : Option<& str>;
+ b = None;
+ let mut d = MyStruct{ x: None, y: 1};
+ let mut e = MyStruct{ x: None, y: 1};
+ (|| {
+ (|| {
+ // This will not trigger a warning for unused variable as
+ // d.x will be treated as a Non-tracked place
+ d.x = Some("d1");
+ d.x = Some("d2");
+ a = Some("d1"); //~ WARN value assigned to `a` is never read
+ a = Some("d2");
+ })();
+ (move || {
+ // This will not trigger a warning for unused variable as
+ //e.x will be treated as a Non-tracked place
+ e.x = Some("e1");
+ e.x = Some("e2");
+ b = Some("e1"); //~ WARN value assigned to `b` is never read
+ //~| WARN unused variable: `b`
+ b = Some("e2"); //~ WARN value assigned to `b` is never read
+ })();
+ })();
+}
+
+fn main() {}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.stderr
new file mode 100644
index 000000000..7e767cba3
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.stderr
@@ -0,0 +1,65 @@
+warning: value captured by `a` is never read
+ --> $DIR/liveness.rs:24:9
+ |
+LL | a = 1;
+ | ^
+ |
+note: the lint level is defined here
+ --> $DIR/liveness.rs:5:9
+ |
+LL | #![warn(unused)]
+ | ^^^^^^
+ = note: `#[warn(unused_assignments)]` implied by `#[warn(unused)]`
+ = help: did you mean to capture by reference instead?
+
+warning: unused variable: `a`
+ --> $DIR/liveness.rs:33:9
+ |
+LL | a += 1;
+ | ^
+ |
+ = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
+ = help: did you mean to capture by reference instead?
+
+warning: value assigned to `a` is never read
+ --> $DIR/liveness.rs:53:9
+ |
+LL | a += 1;
+ | ^
+ |
+ = help: maybe it is overwritten before being read?
+
+warning: value assigned to `a` is never read
+ --> $DIR/liveness.rs:77:13
+ |
+LL | a = Some("d1");
+ | ^
+ |
+ = help: maybe it is overwritten before being read?
+
+warning: value assigned to `b` is never read
+ --> $DIR/liveness.rs:85:13
+ |
+LL | b = Some("e1");
+ | ^
+ |
+ = help: maybe it is overwritten before being read?
+
+warning: value assigned to `b` is never read
+ --> $DIR/liveness.rs:87:13
+ |
+LL | b = Some("e2");
+ | ^
+ |
+ = help: maybe it is overwritten before being read?
+
+warning: unused variable: `b`
+ --> $DIR/liveness.rs:85:13
+ |
+LL | b = Some("e1");
+ | ^
+ |
+ = help: did you mean to capture by reference instead?
+
+warning: 7 warnings emitted
+
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.rs
new file mode 100644
index 000000000..465c9476b
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.rs
@@ -0,0 +1,43 @@
+// edition:2021
+
+// check-pass
+#![warn(unused)]
+#![allow(dead_code)]
+
+#[derive(Debug)]
+struct MyStruct {
+ a: i32,
+ b: i32,
+}
+
+pub fn unintentional_copy_one() {
+ let mut a = 1;
+ let mut last = MyStruct{ a: 1, b: 1};
+ let mut f = move |s| {
+ // This will not trigger a warning for unused variable
+ // as last.a will be treated as a Non-tracked place
+ last.a = s;
+ a = s;
+ //~^ WARN value assigned to `a` is never read
+ //~| WARN unused variable: `a`
+ };
+ f(2);
+ f(3);
+ f(4);
+}
+
+pub fn unintentional_copy_two() {
+ let mut a = 1;
+ let mut sum = MyStruct{ a: 1, b: 0};
+ (1..10).for_each(move |x| {
+ // This will not trigger a warning for unused variable
+ // as sum.b will be treated as a Non-tracked place
+ sum.b += x;
+ a += x; //~ WARN unused variable: `a`
+ });
+}
+
+fn main() {
+ unintentional_copy_one();
+ unintentional_copy_two();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.stderr
new file mode 100644
index 000000000..2ac801b49
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.stderr
@@ -0,0 +1,33 @@
+warning: value assigned to `a` is never read
+ --> $DIR/liveness_unintentional_copy.rs:20:9
+ |
+LL | a = s;
+ | ^
+ |
+note: the lint level is defined here
+ --> $DIR/liveness_unintentional_copy.rs:4:9
+ |
+LL | #![warn(unused)]
+ | ^^^^^^
+ = note: `#[warn(unused_assignments)]` implied by `#[warn(unused)]`
+ = help: maybe it is overwritten before being read?
+
+warning: unused variable: `a`
+ --> $DIR/liveness_unintentional_copy.rs:20:9
+ |
+LL | a = s;
+ | ^
+ |
+ = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
+ = help: did you mean to capture by reference instead?
+
+warning: unused variable: `a`
+ --> $DIR/liveness_unintentional_copy.rs:36:9
+ |
+LL | a += x;
+ | ^
+ |
+ = help: did you mean to capture by reference instead?
+
+warning: 3 warnings emitted
+
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 000000000..fa73ff23f
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.rs
@@ -0,0 +1,28 @@
+// edition:2021
+
+// Test that when a borrow checker diagnostics are emitted, it's as precise
+// as the capture by the closure.
+
+#![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 000000000..ac4c9c937
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr
@@ -0,0 +1,17 @@
+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
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.rs
new file mode 100644
index 000000000..3d5a31e8b
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.rs
@@ -0,0 +1,37 @@
+// edition:2021
+
+// Test that we can't mutate a place if we need to deref an imm-borrow
+// to reach it.
+
+fn imm_mut_ref() {
+ let mut x = String::new();
+ let y = String::new();
+ let mref_x = &mut x;
+ let ref_mref_x = &mref_x;
+
+ let c = || {
+ //~^ ERROR: cannot borrow `**ref_mref_x` as mutable, as it is behind a `&` reference
+ **ref_mref_x = y;
+ };
+
+ c();
+}
+
+fn mut_imm_ref() {
+ let x = String::new();
+ let y = String::new();
+ let mut ref_x = &x;
+ let mref_ref_x = &mut ref_x;
+
+ let c = || {
+ //~^ ERROR: cannot borrow `**mref_ref_x` as mutable, as it is behind a `&` reference
+ **mref_ref_x = y;
+ };
+
+ c();
+}
+
+fn main() {
+ imm_mut_ref();
+ mut_imm_ref();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr
new file mode 100644
index 000000000..481d7e585
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr
@@ -0,0 +1,24 @@
+error[E0596]: cannot borrow `**ref_mref_x` as mutable, as it is behind a `&` reference
+ --> $DIR/mut_ref.rs:12:13
+ |
+LL | let ref_mref_x = &mref_x;
+ | ------- help: consider changing this to be a mutable reference: `&mut mref_x`
+LL |
+LL | let c = || {
+ | ^^ `ref_mref_x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+LL |
+LL | **ref_mref_x = y;
+ | ------------ mutable borrow occurs due to use of `**ref_mref_x` in closure
+
+error[E0596]: cannot borrow `**mref_ref_x` as mutable, as it is behind a `&` reference
+ --> $DIR/mut_ref.rs:26:13
+ |
+LL | let c = || {
+ | ^^ cannot borrow as mutable
+LL |
+LL | **mref_ref_x = y;
+ | ------------ mutable borrow occurs due to use of `**mref_ref_x` in closure
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.rs
new file mode 100644
index 000000000..1488f3296
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.rs
@@ -0,0 +1,32 @@
+// edition:2021
+
+// Given how the closure desugaring is implemented (at least at the time of writing this test),
+// we don't need to truncate the captured path to a reference into a packed-struct if the field
+// being referenced will be moved into the closure, since it's safe to move out a field from a
+// packed-struct.
+//
+// However to avoid surprises for the user, or issues when the closure is
+// inlined we will truncate the capture to access just the struct regardless of if the field
+// might get moved into the closure.
+//
+// It is possible for someone to try writing the code that relies on the desugaring to create a ref
+// into a packed-struct. Here we test that the compiler still detects that case.
+fn test_missing_unsafe_warning_on_repr_packed() {
+ #[repr(packed)]
+ struct Foo { x: String }
+
+ let foo = Foo { x: String::new() };
+
+ let c = || {
+ println!("{}", foo.x);
+ //~^ ERROR: reference to packed field is unaligned
+ //~| WARNING: this was previously accepted by the compiler but is being phased out
+ let _z = foo.x;
+ };
+
+ c();
+}
+
+fn main() {
+ test_missing_unsafe_warning_on_repr_packed();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr
new file mode 100644
index 000000000..93abbecf4
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr
@@ -0,0 +1,29 @@
+error: reference to packed field is unaligned
+ --> $DIR/repr_packed.rs:21:24
+ |
+LL | println!("{}", foo.x);
+ | ^^^^^
+ |
+ = note: `#[deny(unaligned_references)]` on by default
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
+ = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+ = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+Future incompatibility report: Future breakage diagnostic:
+error: reference to packed field is unaligned
+ --> $DIR/repr_packed.rs:21:24
+ |
+LL | println!("{}", foo.x);
+ | ^^^^^
+ |
+ = note: `#[deny(unaligned_references)]` on by default
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
+ = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+ = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
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 000000000..ed2d9a3de
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.rs
@@ -0,0 +1,25 @@
+// edition:2021
+
+// Test that borrow checker error is accurate and that min capture pass of the
+// closure analysis is working as expected.
+
+#[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 000000000..06157b2af
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr
@@ -0,0 +1,21 @@
+error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable
+ --> $DIR/simple-struct-min-capture.rs:22:22
+ |
+LL | let mut c = || {
+ | -- mutable borrow occurs here
+LL | p.x += 10;
+ | --- capture is mutable because of use here
+LL | println!("{:?}", p);
+ | - 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
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/union.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/union.rs
new file mode 100644
index 000000000..46b54846e
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/union.rs
@@ -0,0 +1,25 @@
+// edition:2021
+
+// Test that we point to the correct location that results a union being captured.
+// Union is special because it can't be disjointly captured.
+
+union A {
+ y: u32,
+ x: (),
+}
+
+fn main() {
+ let mut a = A { y: 1 };
+ let mut c = || {
+ //~^ borrow of `a.y` occurs here
+ let _ = unsafe { &a.y };
+ let _ = &mut a;
+ //~^ borrow occurs due to use in closure
+ let _ = unsafe { &mut a.y };
+ };
+ a.y = 1;
+ //~^ cannot assign to `a.y` because it is borrowed [E0506]
+ //~| assignment to borrowed `a.y` occurs here
+ c();
+ //~^ borrow later used here
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/union.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/union.stderr
new file mode 100644
index 000000000..7c34e2336
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/union.stderr
@@ -0,0 +1,18 @@
+error[E0506]: cannot assign to `a.y` because it is borrowed
+ --> $DIR/union.rs:20:5
+ |
+LL | let mut c = || {
+ | -- borrow of `a.y` occurs here
+...
+LL | let _ = &mut a;
+ | - borrow occurs due to use in closure
+...
+LL | a.y = 1;
+ | ^^^^^^^ assignment to borrowed `a.y` occurs here
+...
+LL | c();
+ | - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.