summaryrefslogtreecommitdiffstats
path: root/tests/ui/closures/2229_closure_analysis/run_pass
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:03 +0000
commit64d98f8ee037282c35007b64c2649055c56af1db (patch)
tree5492bcf97fce41ee1c0b1cc2add283f3e66cdab0 /tests/ui/closures/2229_closure_analysis/run_pass
parentAdding debian version 1.67.1+dfsg1-1. (diff)
downloadrustc-64d98f8ee037282c35007b64c2649055c56af1db.tar.xz
rustc-64d98f8ee037282c35007b64c2649055c56af1db.zip
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/ui/closures/2229_closure_analysis/run_pass')
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/box.rs92
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/by_value.rs26
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.rs24
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.rs20
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.rs21
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/capture_with_wildcard_match.rs27
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.rs21
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.stderr21
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.rs119
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.stderr39
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.rs23
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.rs11
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/edition.rs23
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.rs37
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/fru_syntax.rs42
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/issue-87378.rs16
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/issue-88372.rs19
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/issue-88431.rs59
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/issue-88476.rs47
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/lit-pattern-matching-with-methods.rs30
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/move_closure.rs93
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.rs33
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.rs31
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.rs28
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/mut_ref.rs54
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.rs43
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/nested-closure.rs36
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/struct-pattern-matching-with-methods.rs49
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/tuple-struct-pattern-matching-with-methods.rs43
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.rs47
-rw-r--r--tests/ui/closures/2229_closure_analysis/run_pass/use_of_mutable_borrow_and_fake_reads.rs11
31 files changed, 1185 insertions, 0 deletions
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/box.rs b/tests/ui/closures/2229_closure_analysis/run_pass/box.rs
new file mode 100644
index 000000000..73aca288f
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/box.rs
@@ -0,0 +1,92 @@
+// edition:2021
+// run-pass
+
+// Test precise capture when using boxes
+
+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/tests/ui/closures/2229_closure_analysis/run_pass/by_value.rs b/tests/ui/closures/2229_closure_analysis/run_pass/by_value.rs
new file mode 100644
index 000000000..f8752fe1c
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/by_value.rs
@@ -0,0 +1,26 @@
+// edition:2021
+// run-pass
+
+// Test that ByValue captures compile successfully especially when the captures are
+// dereferenced within the closure.
+
+#[derive(Debug, Default)]
+struct SomeLargeType;
+struct MuchLargerType([SomeLargeType; 32]);
+
+fn big_box() {
+ let s = MuchLargerType(Default::default());
+ let b = Box::new(s);
+ let t = (b, 10);
+
+ let c = || {
+ let p = t.0.0;
+ println!("{} {:?}", t.1, p);
+ };
+
+ c();
+}
+
+fn main() {
+ big_box();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.rs b/tests/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.rs
new file mode 100644
index 000000000..3cb1eb329
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-struct.rs
@@ -0,0 +1,24 @@
+// edition:2021
+// 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.
+
+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/tests/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.rs b/tests/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.rs
new file mode 100644
index 000000000..0f79b7ae7
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple-mut.rs
@@ -0,0 +1,20 @@
+// edition:2021
+// 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(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/tests/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.rs b/tests/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.rs
new file mode 100644
index 000000000..81f0328b9
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/capture-disjoint-field-tuple.rs
@@ -0,0 +1,21 @@
+// edition:2021
+// 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(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/tests/ui/closures/2229_closure_analysis/run_pass/capture_with_wildcard_match.rs b/tests/ui/closures/2229_closure_analysis/run_pass/capture_with_wildcard_match.rs
new file mode 100644
index 000000000..cea02fbe1
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/capture_with_wildcard_match.rs
@@ -0,0 +1,27 @@
+// edition:2021
+//check-pass
+
+fn test1() {
+ let foo : [Vec<u8>; 3] = ["String".into(), "String".into(), "String".into()];
+ let c = || {
+ match foo { _ => () };
+ };
+ drop(foo);
+ c();
+}
+
+fn test2() {
+ let foo : Option<[Vec<u8>; 3]> = Some(["String".into(), "String".into(), "String".into()]);
+ let c = || {
+ match foo {
+ Some(_) => 1,
+ _ => 2
+ };
+ };
+ c();
+}
+
+fn main() {
+ test1();
+ test2();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.rs b/tests/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.rs
new file mode 100644
index 000000000..5c278bff9
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.rs
@@ -0,0 +1,21 @@
+// edition:2021
+// check-pass
+#![warn(unused)]
+
+fn main() {
+ let t = (String::from("Hello"), String::from("World"));
+ let g = (String::from("Mr"), String::from("Goose"));
+
+ let a = || {
+ let (_, g2) = g;
+ //~^ WARN unused variable: `g2`
+ let c = || {
+ let (_, t2) = t;
+ //~^ WARN unused variable: `t2`
+ };
+
+ c();
+ };
+
+ a();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.stderr b/tests/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.stderr
new file mode 100644
index 000000000..cf8bd7a0a
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.stderr
@@ -0,0 +1,21 @@
+warning: unused variable: `g2`
+ --> $DIR/destructure-pattern-closure-within-closure.rs:10:17
+ |
+LL | let (_, g2) = g;
+ | ^^ help: if this is intentional, prefix it with an underscore: `_g2`
+ |
+note: the lint level is defined here
+ --> $DIR/destructure-pattern-closure-within-closure.rs:3:9
+ |
+LL | #![warn(unused)]
+ | ^^^^^^
+ = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
+
+warning: unused variable: `t2`
+ --> $DIR/destructure-pattern-closure-within-closure.rs:13:21
+ |
+LL | let (_, t2) = t;
+ | ^^ help: if this is intentional, prefix it with an underscore: `_t2`
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.rs b/tests/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.rs
new file mode 100644
index 000000000..dacc2c616
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.rs
@@ -0,0 +1,119 @@
+// edition:2021
+// check-pass
+#![warn(unused)]
+
+struct Point {
+ x: u32,
+ y: u32,
+}
+
+fn test1() {
+ let t = (String::from("Hello"), String::from("World"));
+
+ let c = || {
+ let (t1, t2) = t;
+ //~^ WARN unused variable: `t1`
+ //~| WARN unused variable: `t2`
+ };
+
+ c();
+}
+
+fn test2() {
+ let t = (String::from("Hello"), String::from("World"));
+
+ let c = || {
+ let (t1, _) = t;
+ //~^ WARN unused variable: `t1`
+ };
+
+ c();
+}
+
+fn test3() {
+ let t = (String::from("Hello"), String::from("World"));
+
+ let c = || {
+ let (_, t2) = t;
+ //~^ WARN unused variable: `t2`
+ };
+
+ c();
+}
+
+fn test4() {
+ let t = (String::from("Hello"), String::from("World"));
+
+ let c = || {
+ let (_, _) = t;
+ };
+
+ c();
+}
+
+fn test5() {
+ let t = (String::new(), String::new());
+ let _c = || {
+ let _a = match t {
+ (t1, _) => t1,
+ };
+ };
+}
+
+fn test6() {
+ let t = (String::new(), String::new());
+ let _c = || {
+ let _a = match t {
+ (_, t2) => t2,
+ };
+ };
+}
+
+fn test7() {
+ let t = (String::new(), String::new());
+ let _c = || {
+ let _a = match t {
+ (t1, t2) => (t1, t2),
+ };
+ };
+}
+
+fn test8() {
+ let x = 0;
+ let tup = (1, 2);
+ let p = Point { x: 10, y: 20 };
+
+ let c = || {
+ let _ = x;
+ let Point { x, y } = p;
+ //~^ WARN unused variable: `x`
+ println!("{}", y);
+ let (_, _) = tup;
+ };
+
+ c();
+}
+
+fn test9() {
+ let _z = 9;
+ let t = (String::from("Hello"), String::from("World"));
+
+ let c = || {
+ let (_, t) = t;
+ println!("{}", t);
+ };
+
+ c();
+}
+
+fn main() {
+ test1();
+ test2();
+ test3();
+ test4();
+ test5();
+ test6();
+ test7();
+ test8();
+ test9();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.stderr b/tests/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.stderr
new file mode 100644
index 000000000..7706f68ba
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.stderr
@@ -0,0 +1,39 @@
+warning: unused variable: `t1`
+ --> $DIR/destructure_patterns.rs:14:14
+ |
+LL | let (t1, t2) = t;
+ | ^^ help: if this is intentional, prefix it with an underscore: `_t1`
+ |
+note: the lint level is defined here
+ --> $DIR/destructure_patterns.rs:3:9
+ |
+LL | #![warn(unused)]
+ | ^^^^^^
+ = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
+
+warning: unused variable: `t2`
+ --> $DIR/destructure_patterns.rs:14:18
+ |
+LL | let (t1, t2) = t;
+ | ^^ help: if this is intentional, prefix it with an underscore: `_t2`
+
+warning: unused variable: `t1`
+ --> $DIR/destructure_patterns.rs:26:14
+ |
+LL | let (t1, _) = t;
+ | ^^ help: if this is intentional, prefix it with an underscore: `_t1`
+
+warning: unused variable: `t2`
+ --> $DIR/destructure_patterns.rs:37:17
+ |
+LL | let (_, t2) = t;
+ | ^^ help: if this is intentional, prefix it with an underscore: `_t2`
+
+warning: unused variable: `x`
+ --> $DIR/destructure_patterns.rs:88:21
+ |
+LL | let Point { x, y } = p;
+ | ^ help: try ignoring the field: `x: _`
+
+warning: 5 warnings emitted
+
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.rs b/tests/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.rs
new file mode 100644
index 000000000..03400e0ee
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.rs
@@ -0,0 +1,23 @@
+// edition:2021
+// run-pass
+
+// Tests that if a closure uses individual 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/tests/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.rs b/tests/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.rs
new file mode 100644
index 000000000..477fdd613
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.rs
@@ -0,0 +1,11 @@
+// edition:2021
+// check-pass
+#![feature(rustc_attrs)]
+
+fn main() {
+ let mut x = 1;
+ let c = || {
+ drop(&mut x);
+ match x { _ => () }
+ };
+}
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/edition.rs b/tests/ui/closures/2229_closure_analysis/run_pass/edition.rs
new file mode 100644
index 000000000..20bbe1d89
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/edition.rs
@@ -0,0 +1,23 @@
+// edition:2021
+// run-pass
+
+// Test that edition 2021 enables disjoint capture by default.
+
+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/tests/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.rs b/tests/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.rs
new file mode 100644
index 000000000..e19f5ff1b
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/filter-on-struct-member.rs
@@ -0,0 +1,37 @@
+// edition:2021
+// run-pass
+
+// Test disjoint capture within an impl block
+
+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/tests/ui/closures/2229_closure_analysis/run_pass/fru_syntax.rs b/tests/ui/closures/2229_closure_analysis/run_pass/fru_syntax.rs
new file mode 100644
index 000000000..1286613cb
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/fru_syntax.rs
@@ -0,0 +1,42 @@
+// edition:2021
+// run-pass
+
+// Test that functional record update/struct update syntax works inside
+// a closure when the feature `capture_disjoint_fields` is enabled.
+
+#[derive(Clone)]
+struct S {
+ a: String,
+ b: String,
+}
+
+struct T {
+ a: String,
+ s: S,
+}
+
+fn main() {
+ let a = String::new();
+ let b = String::new();
+ let c = String::new();
+ let s = S {a, b};
+ let t = T {
+ a: c,
+ s: s.clone()
+ };
+
+ let c = || {
+ let s2 = S {
+ a: format!("New s2"),
+ ..s
+ };
+ let s3 = S {
+ a: format!("New s3"),
+ ..t.s
+ };
+ println!("{} {}", s2.a, s2.b);
+ println!("{} {} {}", s3.a, s3.b, t.a);
+ };
+
+ c();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/issue-87378.rs b/tests/ui/closures/2229_closure_analysis/run_pass/issue-87378.rs
new file mode 100644
index 000000000..c64475fda
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/issue-87378.rs
@@ -0,0 +1,16 @@
+// edition:2021
+// check-pass
+
+union Union {
+ value: u64,
+}
+
+fn main() {
+ let u = Union { value: 42 };
+
+ let c = || {
+ unsafe { u.value }
+ };
+
+ c();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/issue-88372.rs b/tests/ui/closures/2229_closure_analysis/run_pass/issue-88372.rs
new file mode 100644
index 000000000..25fbb6cb9
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/issue-88372.rs
@@ -0,0 +1,19 @@
+// edition:2021
+// run-pass
+
+
+fn solve<F>(validate: F) -> Option<u64>
+where
+ F: Fn(&mut [i8; 1]),
+{
+ let mut position: [i8; 1] = [1];
+ Some(0).map(|_| {
+ validate(&mut position);
+ let [_x] = position;
+ 0
+ })
+}
+
+fn main() {
+ solve(|_| ());
+}
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/issue-88431.rs b/tests/ui/closures/2229_closure_analysis/run_pass/issue-88431.rs
new file mode 100644
index 000000000..999620530
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/issue-88431.rs
@@ -0,0 +1,59 @@
+// edition:2021
+// check-pass
+
+use std::collections::HashMap;
+use std::future::Future;
+use std::pin::Pin;
+
+pub struct GameMode {}
+
+struct GameStateManager<'a> {
+ gamestate_stack: Vec<Box<dyn GameState<'a> + 'a>>,
+}
+
+pub trait GameState<'a> {}
+
+async fn construct_gamestate_replay<'a>(
+ _gamemode: &GameMode,
+ _factory: &mut GameStateManager<'a>,
+) -> Box<dyn GameState<'a> + 'a> {
+ unimplemented!()
+}
+
+type FutureGameState<'a, 'b> = Pin<Box<dyn Future<Output = Box<dyn GameState<'a> + 'a>> + 'b>>;
+
+struct MenuOption<'a> {
+ command: Box<dyn for<'b> Fn(&'b mut GameStateManager<'a>) -> FutureGameState<'a, 'b> + 'a>,
+}
+
+impl<'a> MenuOption<'a> {
+ fn new(
+ _command: impl for<'b> Fn(&'b mut GameStateManager<'a>) -> FutureGameState<'a, 'b> + 'a,
+ ) -> Self {
+ unimplemented!()
+ }
+}
+
+struct MenuState<'a> {
+ options: Vec<MenuOption<'a>>,
+}
+
+impl<'a> GameState<'a> for MenuState<'a> {}
+
+pub async fn get_replay_menu<'a>(
+ gamemodes: &'a HashMap<&str, GameMode>,
+) -> Box<dyn GameState<'a> + 'a> {
+ let recordings: Vec<String> = vec![];
+ let _ = recordings
+ .into_iter()
+ .map(|entry| {
+ MenuOption::new(move |f| {
+ Box::pin(construct_gamestate_replay(&gamemodes[entry.as_str()], f))
+ })
+ })
+ .collect::<Vec<_>>();
+
+ todo!()
+}
+
+fn main() {}
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/issue-88476.rs b/tests/ui/closures/2229_closure_analysis/run_pass/issue-88476.rs
new file mode 100644
index 000000000..f44c2af80
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/issue-88476.rs
@@ -0,0 +1,47 @@
+// check-pass
+// edition:2021
+
+use std::rc::Rc;
+
+// Test that we restrict precision when moving not-`Copy` types, if any of the parent paths
+// implement `Drop`. This is to ensure that we don't move out of a type that implements Drop.
+pub fn test1() {
+ struct Foo(Rc<i32>);
+
+ impl Drop for Foo {
+ fn drop(self: &mut Foo) {}
+ }
+
+ let f = Foo(Rc::new(1));
+ let x = move || {
+ println!("{:?}", f.0);
+ };
+
+ x();
+}
+
+
+// Test that we don't restrict precision when moving `Copy` types(i.e. when copying),
+// even if any of the parent paths implement `Drop`.
+pub fn test2() {
+ struct Character {
+ hp: u32,
+ name: String,
+ }
+
+ impl Drop for Character {
+ fn drop(&mut self) {}
+ }
+
+ let character = Character { hp: 100, name: format!("A") };
+
+ let c = move || {
+ println!("{}", character.hp)
+ };
+
+ c();
+
+ println!("{}", character.name);
+}
+
+fn main() {}
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/lit-pattern-matching-with-methods.rs b/tests/ui/closures/2229_closure_analysis/run_pass/lit-pattern-matching-with-methods.rs
new file mode 100644
index 000000000..d2375aa69
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/lit-pattern-matching-with-methods.rs
@@ -0,0 +1,30 @@
+// edition:2021
+//check-pass
+#![warn(unused)]
+#![feature(rustc_attrs)]
+#![feature(btree_drain_filter)]
+
+use std::collections::BTreeMap;
+use std::panic::{catch_unwind, AssertUnwindSafe};
+
+fn main() {
+ let mut map = BTreeMap::new();
+ map.insert("a", ());
+ map.insert("b", ());
+ map.insert("c", ());
+
+ {
+ let mut it = map.drain_filter(|_, _| true);
+ catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err();
+ let result = catch_unwind(AssertUnwindSafe(|| it.next()));
+ assert!(matches!(result, Ok(None)));
+ }
+
+ {
+ let mut it = map.drain_filter(|_, _| true);
+ catch_unwind(AssertUnwindSafe(|| while let Some(_) = it.next() {})).unwrap_err();
+ let result = catch_unwind(AssertUnwindSafe(|| it.next()));
+ assert!(matches!(result, Ok(None)));
+ }
+
+}
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/move_closure.rs b/tests/ui/closures/2229_closure_analysis/run_pass/move_closure.rs
new file mode 100644
index 000000000..f76965bdd
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/move_closure.rs
@@ -0,0 +1,93 @@
+// edition:2021
+// run-pass
+
+// Test that move closures compile properly with `capture_disjoint_fields` enabled.
+
+#![allow(unused)]
+
+fn simple_ref() {
+ let mut s = 10;
+ let ref_s = &mut s;
+
+ let mut c = move || {
+ *ref_s += 10;
+ };
+ c();
+}
+
+fn struct_contains_ref_to_another_struct() {
+ struct S(String);
+ struct T<'a>(&'a mut S);
+
+ let mut s = S("s".into());
+ let t = T(&mut s);
+
+ let mut c = move || {
+ t.0.0 = "new s".into();
+ };
+
+ c();
+}
+
+#[derive(Debug)]
+struct S(String);
+
+#[derive(Debug)]
+struct T(S);
+
+fn no_ref() {
+ let mut t = T(S("s".into()));
+ let mut c = move || {
+ t.0.0 = "new S".into();
+ };
+ c();
+}
+
+fn no_ref_nested() {
+ let mut t = T(S("s".into()));
+ let c = || {
+ println!("{:?}", t.0);
+ let mut c = move || {
+ t.0.0 = "new S".into();
+ println!("{:?}", t.0.0);
+ };
+ c();
+ };
+ c();
+}
+
+// Test that even if a path is moved into the closure, the closure is not FnOnce
+// if the path is not moved by the closure call.
+fn data_moved_but_not_fn_once() {
+ let x = Box::new(10i32);
+
+ let c = move || {
+ // *x has type i32 which is Copy. So even though the box `x` will be moved
+ // into the closure, `x` is never moved when the closure is called, i.e. the
+ // ownership stays with the closure and therefore we can call the function multiple times.
+ let _x = *x;
+ };
+
+ c();
+ c();
+}
+
+// Test that move closures can take ownership of Copy type
+fn returned_closure_owns_copy_type_data() -> impl Fn() -> i32 {
+ let x = 10;
+
+ let c = move || x;
+
+ c
+}
+
+fn main() {
+ simple_ref();
+ struct_contains_ref_to_another_struct();
+ no_ref();
+ no_ref_nested();
+
+ data_moved_but_not_fn_once();
+
+ returned_closure_owns_copy_type_data();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.rs b/tests/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.rs
new file mode 100644
index 000000000..624e0ff22
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.rs
@@ -0,0 +1,33 @@
+// edition:2021
+// run-pass
+
+// Test that closures can capture paths that are more precise than just one level
+// from the root variable.
+//
+// If the closures can handle such precision 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.
+
+#![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/tests/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.rs b/tests/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.rs
new file mode 100644
index 000000000..bd8addd37
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.rs
@@ -0,0 +1,31 @@
+// edition:2021
+// run-pass
+
+#![allow(unused)]
+
+// If the closures can handle such precision 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/tests/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.rs b/tests/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.rs
new file mode 100644
index 000000000..8fc0efb60
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/multilevel-path-3.rs
@@ -0,0 +1,28 @@
+// edition:2021
+// run-pass
+
+#![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/tests/ui/closures/2229_closure_analysis/run_pass/mut_ref.rs b/tests/ui/closures/2229_closure_analysis/run_pass/mut_ref.rs
new file mode 100644
index 000000000..9f0c4d96a
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/mut_ref.rs
@@ -0,0 +1,54 @@
+// edition:2021
+// run-pass
+
+// Test that we can mutate a place through a mut-borrow
+// that is captured by the closure
+
+// Check that we can mutate when one deref is required
+fn mut_ref_1() {
+ let mut x = String::new();
+ let rx = &mut x;
+
+ let mut c = || {
+ *rx = String::new();
+ };
+
+ c();
+}
+
+// Similar example as mut_ref_1, we don't deref the imm-borrow here,
+// and so we are allowed to mutate.
+fn mut_ref_2() {
+ let x = String::new();
+ let y = String::new();
+ let mut ref_x = &x;
+ let m_ref_x = &mut ref_x;
+
+ let mut c = || {
+ *m_ref_x = &y;
+ };
+
+ c();
+}
+
+// Check that we can mutate when multiple derefs of mut-borrows are required to reach
+// the target place.
+// It works because all derefs are mutable, if either of them was an immutable
+// borrow, then we would not be able to deref.
+fn mut_mut_ref() {
+ let mut x = String::new();
+ let mut mref_x = &mut x;
+ let m_mref_x = &mut mref_x;
+
+ let mut c = || {
+ **m_mref_x = String::new();
+ };
+
+ c();
+}
+
+fn main() {
+ mut_ref_1();
+ mut_ref_2();
+ mut_mut_ref();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.rs b/tests/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.rs
new file mode 100644
index 000000000..a85335438
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.rs
@@ -0,0 +1,43 @@
+// edition:2021
+// run-pass
+
+// Test that we can mutate a place through a mut-borrow
+// that is captured by the closure
+
+// More specifically we test that the if the mutable reference isn't root variable of a capture
+// but rather accessed while accessing the precise capture.
+
+fn mut_tuple() {
+ let mut t = (10, 10);
+
+ let t1 = (&mut t, 10);
+
+ let mut c = || {
+ // Mutable because (*t.0) is mutable
+ t1.0.0 += 10;
+ };
+
+ c();
+}
+
+fn mut_tuple_nested() {
+ let mut t = (10, 10);
+
+ let t1 = (&mut t, 10);
+
+ let mut c = || {
+ let mut c = || {
+ // Mutable because (*t.0) is mutable
+ t1.0.0 += 10;
+ };
+
+ c();
+ };
+
+ c();
+}
+
+fn main() {
+ mut_tuple();
+ mut_tuple_nested();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/nested-closure.rs b/tests/ui/closures/2229_closure_analysis/run_pass/nested-closure.rs
new file mode 100644
index 000000000..a80b40bb4
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/nested-closure.rs
@@ -0,0 +1,36 @@
+// edition:2021
+// run-pass
+
+// Test whether if we can do precise capture when using nested clsoure.
+
+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/tests/ui/closures/2229_closure_analysis/run_pass/struct-pattern-matching-with-methods.rs b/tests/ui/closures/2229_closure_analysis/run_pass/struct-pattern-matching-with-methods.rs
new file mode 100644
index 000000000..ed222b314
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/struct-pattern-matching-with-methods.rs
@@ -0,0 +1,49 @@
+// edition:2021
+//check-pass
+#![warn(unused)]
+#![allow(dead_code)]
+#![feature(rustc_attrs)]
+
+#[derive(Debug, Clone, Copy)]
+enum PointType {
+ TwoD { x: u32, y: u32 },
+
+ ThreeD{ x: u32, y: u32, z: u32 }
+}
+
+// Testing struct patterns
+struct Points {
+ points: Vec<PointType>,
+}
+
+impl Points {
+ pub fn test1(&mut self) -> Vec<usize> {
+ (0..self.points.len())
+ .filter_map(|i| {
+ let idx = i as usize;
+ match self.test2(idx) {
+ PointType::TwoD { .. } => Some(i),
+ PointType::ThreeD { .. } => None,
+ }
+ })
+ .collect()
+ }
+
+ pub fn test2(&mut self, i: usize) -> PointType {
+ self.points[i]
+ }
+}
+
+fn main() {
+ let mut points = Points {
+ points: Vec::<PointType>::new()
+ };
+
+ points.points.push(PointType::ThreeD { x:0, y:0, z:0 });
+ points.points.push(PointType::TwoD{ x:0, y:0 });
+ points.points.push(PointType::ThreeD{ x:0, y:0, z:0 });
+ points.points.push(PointType::TwoD{ x:0, y:0 });
+
+ println!("{:?}", points.test1());
+ println!("{:?}", points.points);
+}
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/tuple-struct-pattern-matching-with-methods.rs b/tests/ui/closures/2229_closure_analysis/run_pass/tuple-struct-pattern-matching-with-methods.rs
new file mode 100644
index 000000000..f3f44433c
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/tuple-struct-pattern-matching-with-methods.rs
@@ -0,0 +1,43 @@
+// edition:2021
+//check-pass
+
+#[derive(Copy, Clone)]
+enum PointType {
+ TwoD(u32, u32),
+ ThreeD(u32, u32, u32)
+}
+
+// Testing tuple struct patterns
+struct Points {
+ points: Vec<PointType>,
+}
+
+impl Points {
+ pub fn test1(&mut self) -> Vec<usize> {
+ (0..self.points.len())
+ .filter_map(|i| {
+ match self.test2(i) {
+ PointType::TwoD (..) => Some(i),
+ PointType::ThreeD (..) => None,
+ }
+ })
+ .collect()
+ }
+
+ pub fn test2(&mut self, i: usize) -> PointType {
+ self.points[i]
+ }
+}
+
+fn main() {
+ let mut points = Points {
+ points: Vec::<PointType>::new()
+ };
+
+ points.points.push(PointType::ThreeD(0,0,0));
+ points.points.push(PointType::TwoD(0,0));
+ points.points.push(PointType::ThreeD(0,0,1));
+ points.points.push(PointType::TwoD(0,1));
+
+ println!("{:?}", points.test1());
+}
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.rs b/tests/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.rs
new file mode 100644
index 000000000..3f7ddf93f
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/unsafe_ptr.rs
@@ -0,0 +1,47 @@
+// edition:2021
+// run-pass
+
+// Test that we can use raw ptrs when using `capture_disjoint_fields`.
+
+#![allow(dead_code)]
+
+#[derive(Debug)]
+struct S {
+ s: String,
+ t: String,
+}
+
+struct T(*const S);
+
+fn unsafe_imm() {
+ let s = "".into();
+ let t = "".into();
+ let my_speed: Box<S> = Box::new(S { s, t });
+
+ let p : *const S = Box::into_raw(my_speed);
+ let t = T(p);
+
+ let c = || unsafe {
+ println!("{:?}", (*t.0).s);
+ };
+
+ c();
+}
+
+fn unsafe_mut() {
+ let s = "".into();
+ let t = "".into();
+ let mut my_speed: Box<S> = Box::new(S { s, t });
+ let p : *mut S = &mut *my_speed;
+
+ let c = || {
+ let x = unsafe { &mut (*p).s };
+ *x = "s".into();
+ };
+ c();
+}
+
+fn main() {
+ unsafe_mut();
+ unsafe_imm();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/use_of_mutable_borrow_and_fake_reads.rs b/tests/ui/closures/2229_closure_analysis/run_pass/use_of_mutable_borrow_and_fake_reads.rs
new file mode 100644
index 000000000..0206927cc
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/run_pass/use_of_mutable_borrow_and_fake_reads.rs
@@ -0,0 +1,11 @@
+// edition:2021
+//check-pass
+#![feature(rustc_attrs)]
+
+fn main() {
+ let mut x = 0;
+ let c = || {
+ &mut x; // mutable borrow of `x`
+ match x { _ => () } // fake read of `x`
+ };
+}