summaryrefslogtreecommitdiffstats
path: root/tests/ui/closures/2229_closure_analysis/migrations
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/closures/2229_closure_analysis/migrations')
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed88
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/auto_traits.rs87
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr67
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed33
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs32
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr33
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed38
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs38
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed76
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs74
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr45
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs45
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/issue-78720.rs10
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/issue-78720.stderr12
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/issue-86753.rs34
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/issue-90024-adt-correct-subst.rs37
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/macro.fixed25
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/macro.rs25
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/macro.stderr22
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.fixed47
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.rs46
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr41
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed50
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs49
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr26
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed157
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs153
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr118
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/no_migrations.rs81
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/old_name.rs9
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/old_name.stderr10
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/precise.fixed69
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/precise.rs67
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/precise.stderr55
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/precise_no_migrations.rs104
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed229
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/significant_drop.rs220
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr214
-rw-r--r--tests/ui/closures/2229_closure_analysis/migrations/unpin_no_migration.rs13
39 files changed, 2579 insertions, 0 deletions
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed b/tests/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed
new file mode 100644
index 000000000..26703fbf8
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed
@@ -0,0 +1,88 @@
+// run-rustfix
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE: the lint level is defined here
+
+use std::thread;
+
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+/* Test Send Trait Migration */
+struct SendPointer(*mut i32);
+unsafe impl Send for SendPointer {}
+
+fn test_send_trait() {
+ let mut f = 10;
+ let fptr = SendPointer(&mut f as *mut i32);
+ thread::spawn(move || { let _ = &fptr; unsafe {
+ //~^ ERROR: changes to closure capture
+ //~| NOTE: in Rust 2018, this closure implements `Send`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `fptr` to be fully captured
+ *fptr.0 = 20;
+ //~^ NOTE: in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0`
+ } });
+}
+
+/* Test Sync Trait Migration */
+struct CustomInt(*mut i32);
+struct SyncPointer(CustomInt);
+unsafe impl Sync for SyncPointer {}
+unsafe impl Send for CustomInt {}
+
+fn test_sync_trait() {
+ let mut f = 10;
+ let f = CustomInt(&mut f as *mut i32);
+ let fptr = SyncPointer(f);
+ thread::spawn(move || { let _ = &fptr; unsafe {
+ //~^ ERROR: changes to closure capture
+ //~| NOTE: in Rust 2018, this closure implements `Sync`
+ //~| NOTE: in Rust 2018, this closure implements `Send`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `fptr` to be fully captured
+ *fptr.0.0 = 20;
+ //~^ NOTE: in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0.0`
+ } });
+}
+
+/* Test Clone Trait Migration */
+struct S(Foo);
+struct T(i32);
+
+struct U(S, T);
+
+impl Clone for U {
+ fn clone(&self) -> Self {
+ U(S(Foo(0)), T(0))
+ }
+}
+
+fn test_clone_trait() {
+ let f = U(S(Foo(0)), T(0));
+ let c = || {
+ let _ = &f;
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+ //~| NOTE: in Rust 2018, this closure implements `Clone`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `f` to be fully captured
+ let f_1 = f.1;
+ //~^ NOTE: in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.1`
+ println!("{:?}", f_1.0);
+ };
+
+ let c_clone = c.clone();
+
+ c_clone();
+}
+//~^ NOTE: in Rust 2018, `f` is dropped here, but in Rust 2021, only `f.1` will be dropped here as part of the closure
+
+fn main() {
+ test_send_trait();
+ test_sync_trait();
+ test_clone_trait();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/auto_traits.rs b/tests/ui/closures/2229_closure_analysis/migrations/auto_traits.rs
new file mode 100644
index 000000000..932db51d4
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/auto_traits.rs
@@ -0,0 +1,87 @@
+// run-rustfix
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE: the lint level is defined here
+
+use std::thread;
+
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+/* Test Send Trait Migration */
+struct SendPointer(*mut i32);
+unsafe impl Send for SendPointer {}
+
+fn test_send_trait() {
+ let mut f = 10;
+ let fptr = SendPointer(&mut f as *mut i32);
+ thread::spawn(move || unsafe {
+ //~^ ERROR: changes to closure capture
+ //~| NOTE: in Rust 2018, this closure implements `Send`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `fptr` to be fully captured
+ *fptr.0 = 20;
+ //~^ NOTE: in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0`
+ });
+}
+
+/* Test Sync Trait Migration */
+struct CustomInt(*mut i32);
+struct SyncPointer(CustomInt);
+unsafe impl Sync for SyncPointer {}
+unsafe impl Send for CustomInt {}
+
+fn test_sync_trait() {
+ let mut f = 10;
+ let f = CustomInt(&mut f as *mut i32);
+ let fptr = SyncPointer(f);
+ thread::spawn(move || unsafe {
+ //~^ ERROR: changes to closure capture
+ //~| NOTE: in Rust 2018, this closure implements `Sync`
+ //~| NOTE: in Rust 2018, this closure implements `Send`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `fptr` to be fully captured
+ *fptr.0.0 = 20;
+ //~^ NOTE: in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0.0`
+ });
+}
+
+/* Test Clone Trait Migration */
+struct S(Foo);
+struct T(i32);
+
+struct U(S, T);
+
+impl Clone for U {
+ fn clone(&self) -> Self {
+ U(S(Foo(0)), T(0))
+ }
+}
+
+fn test_clone_trait() {
+ let f = U(S(Foo(0)), T(0));
+ let c = || {
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+ //~| NOTE: in Rust 2018, this closure implements `Clone`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `f` to be fully captured
+ let f_1 = f.1;
+ //~^ NOTE: in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.1`
+ println!("{:?}", f_1.0);
+ };
+
+ let c_clone = c.clone();
+
+ c_clone();
+}
+//~^ NOTE: in Rust 2018, `f` is dropped here, but in Rust 2021, only `f.1` will be dropped here as part of the closure
+
+fn main() {
+ test_send_trait();
+ test_sync_trait();
+ test_clone_trait();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr b/tests/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr
new file mode 100644
index 000000000..3a42cc8b8
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr
@@ -0,0 +1,67 @@
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
+ --> $DIR/auto_traits.rs:22:19
+ |
+LL | thread::spawn(move || unsafe {
+ | ^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr` is not fully captured and `fptr.0` does not implement `Send`
+...
+LL | *fptr.0 = 20;
+ | ------- in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0`
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+note: the lint level is defined here
+ --> $DIR/auto_traits.rs:2:9
+ |
+LL | #![deny(rust_2021_incompatible_closure_captures)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: add a dummy let to cause `fptr` to be fully captured
+ |
+LL ~ thread::spawn(move || { let _ = &fptr; unsafe {
+LL |
+ ...
+LL |
+LL ~ } });
+ |
+
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
+ --> $DIR/auto_traits.rs:42:19
+ |
+LL | thread::spawn(move || unsafe {
+ | ^^^^^^^
+ | |
+ | in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr` is not fully captured and `fptr.0.0` does not implement `Send`
+ | in Rust 2018, this closure implements `Sync` as `fptr` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr` is not fully captured and `fptr.0.0` does not implement `Sync`
+...
+LL | *fptr.0.0 = 20;
+ | --------- in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0.0`
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `fptr` to be fully captured
+ |
+LL ~ thread::spawn(move || { let _ = &fptr; unsafe {
+LL |
+ ...
+LL |
+LL ~ } });
+ |
+
+error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+ --> $DIR/auto_traits.rs:67:13
+ |
+LL | let c = || {
+ | ^^ in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f` is not fully captured and `f.1` does not implement `Clone`
+...
+LL | let f_1 = f.1;
+ | --- in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.1`
+...
+LL | }
+ | - in Rust 2018, `f` is dropped here, but in Rust 2021, only `f.1` will be dropped here as part of the closure
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `f` to be fully captured
+ |
+LL ~ let c = || {
+LL + let _ = &f;
+ |
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed b/tests/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed
new file mode 100644
index 000000000..9a6db588c
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed
@@ -0,0 +1,33 @@
+// run-rustfix
+// edition:2018
+// check-pass
+#![warn(rust_2021_compatibility)]
+
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+macro_rules! m {
+ (@ $body:expr) => {{
+ let f = || $body;
+ //~^ WARNING: drop order
+ f();
+ }};
+ ($body:block) => {{
+ m!(@ $body);
+ }};
+}
+
+fn main() {
+ let a = (Foo(0), Foo(1));
+ m!({
+ let _ = &a;
+ //~^ HELP: add a dummy
+ let x = a.0;
+ println!("{:?}", x);
+ });
+}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs b/tests/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs
new file mode 100644
index 000000000..08cc24b4b
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs
@@ -0,0 +1,32 @@
+// run-rustfix
+// edition:2018
+// check-pass
+#![warn(rust_2021_compatibility)]
+
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+macro_rules! m {
+ (@ $body:expr) => {{
+ let f = || $body;
+ //~^ WARNING: drop order
+ f();
+ }};
+ ($body:block) => {{
+ m!(@ $body);
+ }};
+}
+
+fn main() {
+ let a = (Foo(0), Foo(1));
+ m!({
+ //~^ HELP: add a dummy
+ let x = a.0;
+ println!("{:?}", x);
+ });
+}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr b/tests/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr
new file mode 100644
index 000000000..bb17e3a34
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr
@@ -0,0 +1,33 @@
+warning: changes to closure capture in Rust 2021 will affect drop order
+ --> $DIR/closure-body-macro-fragment.rs:16:17
+ |
+LL | let f = || $body;
+ | ^^
+...
+LL | }};
+ | - in Rust 2018, `a` is dropped here, but in Rust 2021, only `a.0` will be dropped here as part of the closure
+...
+LL | / m!({
+LL | |
+LL | | let x = a.0;
+ | | --- in Rust 2018, this closure captures all of `a`, but in Rust 2021, it will only capture `a.0`
+LL | | println!("{:?}", x);
+LL | | });
+ | |______- in this macro invocation
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+note: the lint level is defined here
+ --> $DIR/closure-body-macro-fragment.rs:4:9
+ |
+LL | #![warn(rust_2021_compatibility)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ = note: `#[warn(rust_2021_incompatible_closure_captures)]` implied by `#[warn(rust_2021_compatibility)]`
+ = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add a dummy let to cause `a` to be fully captured
+ |
+LL ~ m!({
+LL + let _ = &a;
+ |
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed b/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed
new file mode 100644
index 000000000..2652bf598
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed
@@ -0,0 +1,38 @@
+// run-pass
+// run-rustfix
+
+#![deny(rust_2021_incompatible_closure_captures)]
+#![allow(unused)]
+
+// Test cases for types that implement an insignificant drop (stlib defined)
+
+macro_rules! test_insig_dtor_for_type {
+ ($t: ty, $disambiguator: ident) => {
+ mod $disambiguator {
+ use std::collections::*;
+ use std::rc::Rc;
+ use std::sync::Mutex;
+
+ fn test_for_type(t: $t) {
+ let tup = (Mutex::new(0), t);
+
+ let _c = || tup.0;
+ }
+ }
+ };
+}
+
+test_insig_dtor_for_type!(i32, prim_i32);
+test_insig_dtor_for_type!(Vec<i32>, vec_i32);
+test_insig_dtor_for_type!(String, string);
+test_insig_dtor_for_type!(Vec<String>, vec_string);
+test_insig_dtor_for_type!(HashMap<String, String>, hash_map);
+test_insig_dtor_for_type!(BTreeMap<String, i32>, btree_map);
+test_insig_dtor_for_type!(LinkedList<String>, linked_list);
+test_insig_dtor_for_type!(Rc<i32>, rc_i32);
+test_insig_dtor_for_type!(Rc<String>, rc_string);
+test_insig_dtor_for_type!(std::vec::IntoIter<String>, vec_into_iter);
+test_insig_dtor_for_type!(btree_map::IntoIter<String, String>, btree_map_into_iter);
+test_insig_dtor_for_type!(std::array::IntoIter<String, 5>, array_into_iter);
+
+fn main() {}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs b/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs
new file mode 100644
index 000000000..2652bf598
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs
@@ -0,0 +1,38 @@
+// run-pass
+// run-rustfix
+
+#![deny(rust_2021_incompatible_closure_captures)]
+#![allow(unused)]
+
+// Test cases for types that implement an insignificant drop (stlib defined)
+
+macro_rules! test_insig_dtor_for_type {
+ ($t: ty, $disambiguator: ident) => {
+ mod $disambiguator {
+ use std::collections::*;
+ use std::rc::Rc;
+ use std::sync::Mutex;
+
+ fn test_for_type(t: $t) {
+ let tup = (Mutex::new(0), t);
+
+ let _c = || tup.0;
+ }
+ }
+ };
+}
+
+test_insig_dtor_for_type!(i32, prim_i32);
+test_insig_dtor_for_type!(Vec<i32>, vec_i32);
+test_insig_dtor_for_type!(String, string);
+test_insig_dtor_for_type!(Vec<String>, vec_string);
+test_insig_dtor_for_type!(HashMap<String, String>, hash_map);
+test_insig_dtor_for_type!(BTreeMap<String, i32>, btree_map);
+test_insig_dtor_for_type!(LinkedList<String>, linked_list);
+test_insig_dtor_for_type!(Rc<i32>, rc_i32);
+test_insig_dtor_for_type!(Rc<String>, rc_string);
+test_insig_dtor_for_type!(std::vec::IntoIter<String>, vec_into_iter);
+test_insig_dtor_for_type!(btree_map::IntoIter<String, String>, btree_map_into_iter);
+test_insig_dtor_for_type!(std::array::IntoIter<String, 5>, array_into_iter);
+
+fn main() {}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed b/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed
new file mode 100644
index 000000000..d985e3bb9
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed
@@ -0,0 +1,76 @@
+// run-rustfix
+
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE: the lint level is defined here
+#![feature(rustc_attrs)]
+#![allow(unused)]
+
+use std::sync::Mutex;
+
+ #[rustc_insignificant_dtor]
+struct InsignificantDropPoint {
+ x: i32,
+ y: Mutex<i32>,
+}
+
+impl Drop for InsignificantDropPoint {
+ fn drop(&mut self) {}
+}
+
+struct SigDrop;
+
+impl Drop for SigDrop {
+ fn drop(&mut self) {}
+}
+
+#[rustc_insignificant_dtor]
+struct GenericStruct<T>(T, T);
+
+impl<T> Drop for GenericStruct<T> {
+ fn drop(&mut self) {}
+}
+
+struct Wrapper<T>(GenericStruct<T>, i32);
+
+// `SigDrop` implements drop and therefore needs to be migrated.
+fn significant_drop_needs_migration() {
+ let t = (SigDrop {}, SigDrop {});
+
+ let c = || {
+ let _ = &t;
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t` to be fully captured
+ let _t = t.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+
+// Even if a type implements an insignificant drop, if it's
+// elements have a significant drop then the overall type is
+// consdered to have an significant drop. Since the elements
+// of `GenericStruct` implement drop, migration is required.
+fn generic_struct_with_significant_drop_needs_migration() {
+ let t = Wrapper(GenericStruct(SigDrop {}, SigDrop {}), 5);
+
+ // move is used to force i32 to be copied instead of being a ref
+ let c = move || {
+ let _ = &t;
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t` to be fully captured
+ let _t = t.1;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.1`
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure
+
+fn main() {
+ significant_drop_needs_migration();
+ generic_struct_with_significant_drop_needs_migration();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs b/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs
new file mode 100644
index 000000000..f95d34eeb
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs
@@ -0,0 +1,74 @@
+// run-rustfix
+
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE: the lint level is defined here
+#![feature(rustc_attrs)]
+#![allow(unused)]
+
+use std::sync::Mutex;
+
+ #[rustc_insignificant_dtor]
+struct InsignificantDropPoint {
+ x: i32,
+ y: Mutex<i32>,
+}
+
+impl Drop for InsignificantDropPoint {
+ fn drop(&mut self) {}
+}
+
+struct SigDrop;
+
+impl Drop for SigDrop {
+ fn drop(&mut self) {}
+}
+
+#[rustc_insignificant_dtor]
+struct GenericStruct<T>(T, T);
+
+impl<T> Drop for GenericStruct<T> {
+ fn drop(&mut self) {}
+}
+
+struct Wrapper<T>(GenericStruct<T>, i32);
+
+// `SigDrop` implements drop and therefore needs to be migrated.
+fn significant_drop_needs_migration() {
+ let t = (SigDrop {}, SigDrop {});
+
+ let c = || {
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t` to be fully captured
+ let _t = t.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+
+// Even if a type implements an insignificant drop, if it's
+// elements have a significant drop then the overall type is
+// consdered to have an significant drop. Since the elements
+// of `GenericStruct` implement drop, migration is required.
+fn generic_struct_with_significant_drop_needs_migration() {
+ let t = Wrapper(GenericStruct(SigDrop {}, SigDrop {}), 5);
+
+ // move is used to force i32 to be copied instead of being a ref
+ let c = move || {
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t` to be fully captured
+ let _t = t.1;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.1`
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure
+
+fn main() {
+ significant_drop_needs_migration();
+ generic_struct_with_significant_drop_needs_migration();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr b/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr
new file mode 100644
index 000000000..a0795c129
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr
@@ -0,0 +1,45 @@
+error: changes to closure capture in Rust 2021 will affect drop order
+ --> $DIR/insignificant_drop_attr_migrations.rs:39:13
+ |
+LL | let c = || {
+ | ^^
+...
+LL | let _t = t.0;
+ | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+...
+LL | }
+ | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+note: the lint level is defined here
+ --> $DIR/insignificant_drop_attr_migrations.rs:3:9
+ |
+LL | #![deny(rust_2021_incompatible_closure_captures)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: add a dummy let to cause `t` to be fully captured
+ |
+LL ~ let c = || {
+LL + let _ = &t;
+ |
+
+error: changes to closure capture in Rust 2021 will affect drop order
+ --> $DIR/insignificant_drop_attr_migrations.rs:59:13
+ |
+LL | let c = move || {
+ | ^^^^^^^
+...
+LL | let _t = t.1;
+ | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.1`
+...
+LL | }
+ | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `t` to be fully captured
+ |
+LL ~ let c = move || {
+LL + let _ = &t;
+ |
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs b/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs
new file mode 100644
index 000000000..3f184a67f
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs
@@ -0,0 +1,45 @@
+// run-pass
+
+#![deny(rust_2021_incompatible_closure_captures)]
+#![feature(rustc_attrs)]
+#![allow(unused)]
+#[rustc_insignificant_dtor]
+
+struct InsignificantDropPoint {
+ x: i32,
+ y: i32,
+}
+
+impl Drop for InsignificantDropPoint {
+ fn drop(&mut self) {}
+}
+
+struct GenericStruct<T>(T, T);
+
+// No drop reordering is required as the elements of `t` implement insignificant drop
+fn insignificant_drop_does_not_need_migration() {
+ let t = (InsignificantDropPoint { x: 4, y: 9 }, InsignificantDropPoint { x: 4, y: 9 });
+
+ let c = || {
+ let _t = t.0;
+ };
+
+ c();
+}
+
+// Generic struct whose elements don't have significant drops don't need drop reordering
+fn generic_struct_with_insignificant_drop_does_not_need_migration() {
+ let t =
+ GenericStruct(InsignificantDropPoint { x: 4, y: 9 }, InsignificantDropPoint { x: 4, y: 9 });
+
+ let c = || {
+ let _t = t.0;
+ };
+
+ c();
+}
+
+fn main() {
+ insignificant_drop_does_not_need_migration();
+ generic_struct_with_insignificant_drop_does_not_need_migration();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.rs b/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.rs
new file mode 100644
index 000000000..ff5d28461
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.rs
@@ -0,0 +1,10 @@
+// run-pass
+
+#![warn(rust_2021_incompatible_closure_captures)]
+
+fn main() {
+ if let a = "" {
+ //~^ WARNING: irrefutable `if let` pattern
+ drop(|_: ()| drop(a));
+ }
+}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.stderr b/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.stderr
new file mode 100644
index 000000000..36a80e694
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.stderr
@@ -0,0 +1,12 @@
+warning: irrefutable `if let` pattern
+ --> $DIR/issue-78720.rs:6:8
+ |
+LL | if let a = "" {
+ | ^^^^^^^^^^
+ |
+ = note: this pattern will always match, so the `if let` is useless
+ = help: consider replacing the `if let` with a `let`
+ = note: `#[warn(irrefutable_let_patterns)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/issue-86753.rs b/tests/ui/closures/2229_closure_analysis/migrations/issue-86753.rs
new file mode 100644
index 000000000..fce9cac62
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/issue-86753.rs
@@ -0,0 +1,34 @@
+// edition:2018
+// check-pass
+
+#![warn(rust_2021_compatibility)]
+
+use std::future::Future;
+
+struct Runtime;
+
+impl Runtime {
+ pub fn block_on<F: Future>(&self, _future: F) -> F::Output {
+ unimplemented!()
+ }
+}
+
+pub fn http<F, Fut>(_func: F)
+where
+ F: Fn() -> Fut,
+ Fut: Future<Output = ()>,
+{
+ let rt = Runtime {};
+ let srv = rt.block_on(async move { serve(move || async move { unimplemented!() }) });
+ let _ = || rt.block_on(async { srv });
+}
+
+pub struct Server<S> {
+ _marker: std::marker::PhantomData<S>,
+}
+
+pub fn serve<S>(_new_service: S) -> Server<S> {
+ unimplemented!()
+}
+
+fn main() { }
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/issue-90024-adt-correct-subst.rs b/tests/ui/closures/2229_closure_analysis/migrations/issue-90024-adt-correct-subst.rs
new file mode 100644
index 000000000..ed8cb042b
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/issue-90024-adt-correct-subst.rs
@@ -0,0 +1,37 @@
+// Test that rustc doesn't ICE as in #90024.
+// check-pass
+// edition=2018
+
+#![warn(rust_2021_incompatible_closure_captures)]
+
+// Checks there's no double-subst into the generic args, otherwise we get OOB
+// MCVE by @lqd
+pub struct Graph<N, E, Ix> {
+ _edges: E,
+ _nodes: N,
+ _ix: Vec<Ix>,
+}
+fn graph<N, E>() -> Graph<N, E, i32> {
+ todo!()
+}
+fn first_ice() {
+ let g = graph::<i32, i32>();
+ let _ = || g;
+}
+
+// Checks that there is a subst into the fields, otherwise we get normalization error
+// MCVE by @cuviper
+use std::iter::Empty;
+struct Foo<I: Iterator> {
+ data: Vec<I::Item>,
+}
+pub fn second_ice() {
+ let v = Foo::<Empty<()>> { data: vec![] };
+
+ (|| v.data[0])();
+}
+
+pub fn main() {
+ first_ice();
+ second_ice();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/macro.fixed b/tests/ui/closures/2229_closure_analysis/migrations/macro.fixed
new file mode 100644
index 000000000..31fe494dc
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/macro.fixed
@@ -0,0 +1,25 @@
+// run-rustfix
+
+// See https://github.com/rust-lang/rust/issues/87955
+
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE: the lint level is defined here
+
+
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+fn main() {
+ let a = (Foo(0), Foo(1));
+ let _ = || { let _ = &a; dbg!(a.0) };
+ //~^ ERROR: drop order
+ //~| NOTE: will only capture `a.0`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `a` to be fully captured
+}
+//~^ NOTE: dropped here
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/macro.rs b/tests/ui/closures/2229_closure_analysis/migrations/macro.rs
new file mode 100644
index 000000000..0f0c49749
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/macro.rs
@@ -0,0 +1,25 @@
+// run-rustfix
+
+// See https://github.com/rust-lang/rust/issues/87955
+
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE: the lint level is defined here
+
+
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+fn main() {
+ let a = (Foo(0), Foo(1));
+ let _ = || dbg!(a.0);
+ //~^ ERROR: drop order
+ //~| NOTE: will only capture `a.0`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `a` to be fully captured
+}
+//~^ NOTE: dropped here
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/macro.stderr b/tests/ui/closures/2229_closure_analysis/migrations/macro.stderr
new file mode 100644
index 000000000..c17edce72
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/macro.stderr
@@ -0,0 +1,22 @@
+error: changes to closure capture in Rust 2021 will affect drop order
+ --> $DIR/macro.rs:19:13
+ |
+LL | let _ = || dbg!(a.0);
+ | ^^ --- in Rust 2018, this closure captures all of `a`, but in Rust 2021, it will only capture `a.0`
+...
+LL | }
+ | - in Rust 2018, `a` is dropped here, but in Rust 2021, only `a.0` will be dropped here as part of the closure
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+note: the lint level is defined here
+ --> $DIR/macro.rs:5:9
+ |
+LL | #![deny(rust_2021_incompatible_closure_captures)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: add a dummy let to cause `a` to be fully captured
+ |
+LL | let _ = || { let _ = &a; dbg!(a.0) };
+ | +++++++++++++ +
+
+error: aborting due to previous error
+
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.fixed b/tests/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.fixed
new file mode 100644
index 000000000..ce8b60725
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.fixed
@@ -0,0 +1,47 @@
+// run-rustfix
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE: the lint level is defined here
+
+// Test the two possible cases for automated migartion using rustfix
+// - Closure contains a block i.e. `|| { .. };`
+// - Closure contains just an expr `|| ..;`
+
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+fn closure_contains_block() {
+ let t = (Foo(0), Foo(0));
+ let c = || {
+ let _ = &t;
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t` to be fully captured
+ let _t = t.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+
+fn closure_doesnt_contain_block() {
+ let t = (Foo(0), Foo(0));
+ let c = || { let _ = &t; t.0 };
+ //~^ ERROR: drop order
+ //~| NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t` to be fully captured
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+
+fn main() {
+ closure_contains_block();
+ closure_doesnt_contain_block();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.rs b/tests/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.rs
new file mode 100644
index 000000000..2237bebd7
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.rs
@@ -0,0 +1,46 @@
+// run-rustfix
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE: the lint level is defined here
+
+// Test the two possible cases for automated migartion using rustfix
+// - Closure contains a block i.e. `|| { .. };`
+// - Closure contains just an expr `|| ..;`
+
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+fn closure_contains_block() {
+ let t = (Foo(0), Foo(0));
+ let c = || {
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t` to be fully captured
+ let _t = t.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+
+fn closure_doesnt_contain_block() {
+ let t = (Foo(0), Foo(0));
+ let c = || t.0;
+ //~^ ERROR: drop order
+ //~| NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t` to be fully captured
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+
+fn main() {
+ closure_contains_block();
+ closure_doesnt_contain_block();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr b/tests/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr
new file mode 100644
index 000000000..94526487e
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr
@@ -0,0 +1,41 @@
+error: changes to closure capture in Rust 2021 will affect drop order
+ --> $DIR/migrations_rustfix.rs:19:13
+ |
+LL | let c = || {
+ | ^^
+...
+LL | let _t = t.0;
+ | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+...
+LL | }
+ | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+note: the lint level is defined here
+ --> $DIR/migrations_rustfix.rs:2:9
+ |
+LL | #![deny(rust_2021_incompatible_closure_captures)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: add a dummy let to cause `t` to be fully captured
+ |
+LL ~ let c = || {
+LL + let _ = &t;
+ |
+
+error: changes to closure capture in Rust 2021 will affect drop order
+ --> $DIR/migrations_rustfix.rs:33:13
+ |
+LL | let c = || t.0;
+ | ^^ --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+...
+LL | }
+ | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `t` to be fully captured
+ |
+LL | let c = || { let _ = &t; t.0 };
+ | +++++++++++++ +
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed b/tests/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed
new file mode 100644
index 000000000..ff2244a8e
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed
@@ -0,0 +1,50 @@
+// run-rustfix
+// needs-unwind
+
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE: the lint level is defined here
+#![feature(fn_traits)]
+#![feature(never_type)]
+
+use std::panic;
+
+fn foo_diverges() -> ! {
+ panic!()
+}
+
+fn assert_panics<F>(f: F)
+where
+ F: FnOnce(),
+{
+ let f = panic::AssertUnwindSafe(f);
+ let result = panic::catch_unwind(move || {
+ let _ = &f;
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+ //~| NOTE: in Rust 2018, this closure implements `UnwindSafe`
+ //~| NOTE: in Rust 2018, this closure implements `RefUnwindSafe`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `f` to be fully captured
+ f.0()
+ //~^ NOTE: in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.0`
+ });
+ if let Ok(..) = result {
+ panic!("diverging function returned");
+ }
+}
+
+fn test_fn_ptr_panic<T>(mut t: T)
+where
+ T: Fn() -> !,
+{
+ let as_fn = <T as Fn<()>>::call;
+ assert_panics(|| as_fn(&t, ()));
+ let as_fn_mut = <T as FnMut<()>>::call_mut;
+ assert_panics(|| as_fn_mut(&mut t, ()));
+ let as_fn_once = <T as FnOnce<()>>::call_once;
+ assert_panics(|| as_fn_once(t, ()));
+}
+
+fn main() {
+ test_fn_ptr_panic(foo_diverges);
+ test_fn_ptr_panic(foo_diverges as fn() -> !);
+}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs b/tests/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs
new file mode 100644
index 000000000..52e96d013
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs
@@ -0,0 +1,49 @@
+// run-rustfix
+// needs-unwind
+
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE: the lint level is defined here
+#![feature(fn_traits)]
+#![feature(never_type)]
+
+use std::panic;
+
+fn foo_diverges() -> ! {
+ panic!()
+}
+
+fn assert_panics<F>(f: F)
+where
+ F: FnOnce(),
+{
+ let f = panic::AssertUnwindSafe(f);
+ let result = panic::catch_unwind(move || {
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+ //~| NOTE: in Rust 2018, this closure implements `UnwindSafe`
+ //~| NOTE: in Rust 2018, this closure implements `RefUnwindSafe`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `f` to be fully captured
+ f.0()
+ //~^ NOTE: in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.0`
+ });
+ if let Ok(..) = result {
+ panic!("diverging function returned");
+ }
+}
+
+fn test_fn_ptr_panic<T>(mut t: T)
+where
+ T: Fn() -> !,
+{
+ let as_fn = <T as Fn<()>>::call;
+ assert_panics(|| as_fn(&t, ()));
+ let as_fn_mut = <T as FnMut<()>>::call_mut;
+ assert_panics(|| as_fn_mut(&mut t, ()));
+ let as_fn_once = <T as FnOnce<()>>::call_once;
+ assert_panics(|| as_fn_once(t, ()));
+}
+
+fn main() {
+ test_fn_ptr_panic(foo_diverges);
+ test_fn_ptr_panic(foo_diverges as fn() -> !);
+}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr b/tests/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr
new file mode 100644
index 000000000..e10898f98
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr
@@ -0,0 +1,26 @@
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
+ --> $DIR/mir_calls_to_shims.rs:20:38
+ |
+LL | let result = panic::catch_unwind(move || {
+ | ^^^^^^^
+ | |
+ | in Rust 2018, this closure implements `RefUnwindSafe` as `f` implements `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `RefUnwindSafe` because `f` is not fully captured and `f.0` does not implement `RefUnwindSafe`
+ | in Rust 2018, this closure implements `UnwindSafe` as `f` implements `UnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe` because `f` is not fully captured and `f.0` does not implement `UnwindSafe`
+...
+LL | f.0()
+ | --- in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.0`
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+note: the lint level is defined here
+ --> $DIR/mir_calls_to_shims.rs:4:9
+ |
+LL | #![deny(rust_2021_incompatible_closure_captures)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: add a dummy let to cause `f` to be fully captured
+ |
+LL ~ let result = panic::catch_unwind(move || {
+LL + let _ = &f;
+ |
+
+error: aborting due to previous error
+
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed b/tests/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed
new file mode 100644
index 000000000..173dd2e2c
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed
@@ -0,0 +1,157 @@
+// run-rustfix
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE: the lint level is defined here
+
+use std::thread;
+
+#[derive(Debug)]
+struct Foo(String);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+impl Foo {
+ fn from(s: &str) -> Self {
+ Self(String::from(s))
+ }
+}
+
+struct S(#[allow(unused_tuple_struct_fields)] Foo);
+
+#[derive(Clone)]
+struct T(#[allow(unused_tuple_struct_fields)] i32);
+
+struct U(S, T);
+
+impl Clone for U {
+ fn clone(&self) -> Self {
+ U(S(Foo::from("Hello World")), T(0))
+ }
+}
+
+fn test_multi_issues() {
+ let f1 = U(S(Foo::from("foo")), T(0));
+ let f2 = U(S(Foo::from("bar")), T(0));
+ let c = || {
+ let _ = (&f1, &f2);
+ //~^ ERROR: changes to closure capture in Rust 2021
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `f1`, `f2` to be fully captured
+ let _f_1 = f1.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
+ let _f_2 = f2.1;
+ //~^ NOTE: in Rust 2018, this closure captures all of `f2`, but in Rust 2021, it will only capture `f2.1`
+ };
+
+ let c_clone = c.clone();
+
+ c_clone();
+}
+//~^ NOTE: in Rust 2018, `f2` is dropped here, but in Rust 2021, only `f2.1` will be dropped here as part of the closure
+
+fn test_capturing_all_disjoint_fields_individually() {
+ let f1 = U(S(Foo::from("foo")), T(0));
+ let c = || {
+ let _ = &f1;
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `f1` to be fully captured
+ let _f_1 = f1.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
+ let _f_2 = f1.1;
+ };
+
+ let c_clone = c.clone();
+
+ c_clone();
+}
+
+struct U1(S, T, S);
+
+impl Clone for U1 {
+ fn clone(&self) -> Self {
+ U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")))
+ }
+}
+
+fn test_capturing_several_disjoint_fields_individually_1() {
+ let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
+ let c = || {
+ let _ = &f1;
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `f1` to be fully captured
+ let _f_0 = f1.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
+ let _f_2 = f1.2;
+ //~^ NOTE: in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.2`
+ };
+
+ let c_clone = c.clone();
+
+ c_clone();
+}
+
+fn test_capturing_several_disjoint_fields_individually_2() {
+ let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
+ let c = || {
+ let _ = &f1;
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `f1` to be fully captured
+ let _f_0 = f1.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
+ let _f_1 = f1.1;
+ //~^ NOTE: in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.1`
+ };
+
+ let c_clone = c.clone();
+
+ c_clone();
+}
+//~^ NOTE: in Rust 2018, `f1` is dropped here, but in Rust 2021, only `f1.1` will be dropped here as part of the closure
+//~| NOTE: in Rust 2018, `f1` is dropped here, but in Rust 2021, only `f1.0` will be dropped here as part of the closure
+
+struct SendPointer(*mut i32);
+unsafe impl Send for SendPointer {}
+
+struct CustomInt(*mut i32);
+struct SyncPointer(CustomInt);
+unsafe impl Sync for SyncPointer {}
+unsafe impl Send for CustomInt {}
+
+fn test_multi_traits_issues() {
+ let mut f1 = 10;
+ let f1 = CustomInt(&mut f1 as *mut i32);
+ let fptr1 = SyncPointer(f1);
+
+ let mut f2 = 10;
+ let fptr2 = SendPointer(&mut f2 as *mut i32);
+ thread::spawn(move || { let _ = (&fptr1, &fptr2); unsafe {
+ //~^ ERROR: changes to closure capture in Rust 2021
+ //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`
+ //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`
+ //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `fptr1`, `fptr2` to be fully captured
+ *fptr1.0.0 = 20;
+ //~^ NOTE: in Rust 2018, this closure captures all of `fptr1`, but in Rust 2021, it will only capture `fptr1.0.0`
+ *fptr2.0 = 20;
+ //~^ NOTE: in Rust 2018, this closure captures all of `fptr2`, but in Rust 2021, it will only capture `fptr2.0`
+ } });
+}
+
+fn main() {
+ test_multi_issues();
+ test_capturing_all_disjoint_fields_individually();
+ test_capturing_several_disjoint_fields_individually_1();
+ test_capturing_several_disjoint_fields_individually_2();
+ test_multi_traits_issues();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs b/tests/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs
new file mode 100644
index 000000000..cfc4555ca
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs
@@ -0,0 +1,153 @@
+// run-rustfix
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE: the lint level is defined here
+
+use std::thread;
+
+#[derive(Debug)]
+struct Foo(String);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+impl Foo {
+ fn from(s: &str) -> Self {
+ Self(String::from(s))
+ }
+}
+
+struct S(#[allow(unused_tuple_struct_fields)] Foo);
+
+#[derive(Clone)]
+struct T(#[allow(unused_tuple_struct_fields)] i32);
+
+struct U(S, T);
+
+impl Clone for U {
+ fn clone(&self) -> Self {
+ U(S(Foo::from("Hello World")), T(0))
+ }
+}
+
+fn test_multi_issues() {
+ let f1 = U(S(Foo::from("foo")), T(0));
+ let f2 = U(S(Foo::from("bar")), T(0));
+ let c = || {
+ //~^ ERROR: changes to closure capture in Rust 2021
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `f1`, `f2` to be fully captured
+ let _f_1 = f1.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
+ let _f_2 = f2.1;
+ //~^ NOTE: in Rust 2018, this closure captures all of `f2`, but in Rust 2021, it will only capture `f2.1`
+ };
+
+ let c_clone = c.clone();
+
+ c_clone();
+}
+//~^ NOTE: in Rust 2018, `f2` is dropped here, but in Rust 2021, only `f2.1` will be dropped here as part of the closure
+
+fn test_capturing_all_disjoint_fields_individually() {
+ let f1 = U(S(Foo::from("foo")), T(0));
+ let c = || {
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `f1` to be fully captured
+ let _f_1 = f1.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
+ let _f_2 = f1.1;
+ };
+
+ let c_clone = c.clone();
+
+ c_clone();
+}
+
+struct U1(S, T, S);
+
+impl Clone for U1 {
+ fn clone(&self) -> Self {
+ U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")))
+ }
+}
+
+fn test_capturing_several_disjoint_fields_individually_1() {
+ let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
+ let c = || {
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `f1` to be fully captured
+ let _f_0 = f1.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
+ let _f_2 = f1.2;
+ //~^ NOTE: in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.2`
+ };
+
+ let c_clone = c.clone();
+
+ c_clone();
+}
+
+fn test_capturing_several_disjoint_fields_individually_2() {
+ let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
+ let c = || {
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `f1` to be fully captured
+ let _f_0 = f1.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
+ let _f_1 = f1.1;
+ //~^ NOTE: in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.1`
+ };
+
+ let c_clone = c.clone();
+
+ c_clone();
+}
+//~^ NOTE: in Rust 2018, `f1` is dropped here, but in Rust 2021, only `f1.1` will be dropped here as part of the closure
+//~| NOTE: in Rust 2018, `f1` is dropped here, but in Rust 2021, only `f1.0` will be dropped here as part of the closure
+
+struct SendPointer(*mut i32);
+unsafe impl Send for SendPointer {}
+
+struct CustomInt(*mut i32);
+struct SyncPointer(CustomInt);
+unsafe impl Sync for SyncPointer {}
+unsafe impl Send for CustomInt {}
+
+fn test_multi_traits_issues() {
+ let mut f1 = 10;
+ let f1 = CustomInt(&mut f1 as *mut i32);
+ let fptr1 = SyncPointer(f1);
+
+ let mut f2 = 10;
+ let fptr2 = SendPointer(&mut f2 as *mut i32);
+ thread::spawn(move || unsafe {
+ //~^ ERROR: changes to closure capture in Rust 2021
+ //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`
+ //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`
+ //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `fptr1`, `fptr2` to be fully captured
+ *fptr1.0.0 = 20;
+ //~^ NOTE: in Rust 2018, this closure captures all of `fptr1`, but in Rust 2021, it will only capture `fptr1.0.0`
+ *fptr2.0 = 20;
+ //~^ NOTE: in Rust 2018, this closure captures all of `fptr2`, but in Rust 2021, it will only capture `fptr2.0`
+ });
+}
+
+fn main() {
+ test_multi_issues();
+ test_capturing_all_disjoint_fields_individually();
+ test_capturing_several_disjoint_fields_individually_1();
+ test_capturing_several_disjoint_fields_individually_2();
+ test_multi_traits_issues();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr b/tests/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr
new file mode 100644
index 000000000..efb264447
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr
@@ -0,0 +1,118 @@
+error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+ --> $DIR/multi_diagnostics.rs:37:13
+ |
+LL | let c = || {
+ | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone`
+...
+LL | let _f_1 = f1.0;
+ | ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
+LL |
+LL | let _f_2 = f2.1;
+ | ---- in Rust 2018, this closure captures all of `f2`, but in Rust 2021, it will only capture `f2.1`
+...
+LL | }
+ | - in Rust 2018, `f2` is dropped here, but in Rust 2021, only `f2.1` will be dropped here as part of the closure
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+note: the lint level is defined here
+ --> $DIR/multi_diagnostics.rs:2:9
+ |
+LL | #![deny(rust_2021_incompatible_closure_captures)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: add a dummy let to cause `f1`, `f2` to be fully captured
+ |
+LL ~ let c = || {
+LL + let _ = (&f1, &f2);
+ |
+
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
+ --> $DIR/multi_diagnostics.rs:56:13
+ |
+LL | let c = || {
+ | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone`
+...
+LL | let _f_1 = f1.0;
+ | ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `f1` to be fully captured
+ |
+LL ~ let c = || {
+LL + let _ = &f1;
+ |
+
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
+ --> $DIR/multi_diagnostics.rs:81:13
+ |
+LL | let c = || {
+ | ^^
+ | |
+ | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone`
+ | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.2` does not implement `Clone`
+...
+LL | let _f_0 = f1.0;
+ | ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
+LL |
+LL | let _f_2 = f1.2;
+ | ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.2`
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `f1` to be fully captured
+ |
+LL ~ let c = || {
+LL + let _ = &f1;
+ |
+
+error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+ --> $DIR/multi_diagnostics.rs:100:13
+ |
+LL | let c = || {
+ | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone`
+...
+LL | let _f_0 = f1.0;
+ | ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
+LL |
+LL | let _f_1 = f1.1;
+ | ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.1`
+...
+LL | }
+ | -
+ | |
+ | in Rust 2018, `f1` is dropped here, but in Rust 2021, only `f1.0` will be dropped here as part of the closure
+ | in Rust 2018, `f1` is dropped here, but in Rust 2021, only `f1.1` will be dropped here as part of the closure
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `f1` to be fully captured
+ |
+LL ~ let c = || {
+LL + let _ = &f1;
+ |
+
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
+ --> $DIR/multi_diagnostics.rs:133:19
+ |
+LL | thread::spawn(move || unsafe {
+ | ^^^^^^^
+ | |
+ | in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr1` is not fully captured and `fptr1.0.0` does not implement `Send`
+ | in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr1` is not fully captured and `fptr1.0.0` does not implement `Sync`
+ | in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr2` is not fully captured and `fptr2.0` does not implement `Send`
+...
+LL | *fptr1.0.0 = 20;
+ | ---------- in Rust 2018, this closure captures all of `fptr1`, but in Rust 2021, it will only capture `fptr1.0.0`
+LL |
+LL | *fptr2.0 = 20;
+ | -------- in Rust 2018, this closure captures all of `fptr2`, but in Rust 2021, it will only capture `fptr2.0`
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `fptr1`, `fptr2` to be fully captured
+ |
+LL ~ thread::spawn(move || { let _ = (&fptr1, &fptr2); unsafe {
+LL |
+ ...
+LL |
+LL ~ } });
+ |
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/no_migrations.rs b/tests/ui/closures/2229_closure_analysis/migrations/no_migrations.rs
new file mode 100644
index 000000000..8b75e226a
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/no_migrations.rs
@@ -0,0 +1,81 @@
+// run-pass
+
+// Set of test cases that don't need migrations
+
+#![deny(rust_2021_incompatible_closure_captures)]
+
+// Copy types as copied by the closure instead of being moved into the closure
+// Therefore their drop order isn't tied to the closure and won't be requiring any
+// migrations.
+fn test1_only_copy_types() {
+ let t = (0i32, 0i32);
+
+ let c = || {
+ let _t = t.0;
+ };
+
+ c();
+}
+
+// Same as test1 but using a move closure
+fn test2_only_copy_types_move_closure() {
+ let t = (0i32, 0i32);
+
+ let c = move || {
+ println!("{}", t.0);
+ };
+
+ c();
+}
+
+// Don't need to migrate if captured by ref
+fn test3_only_copy_types_move_closure() {
+ let t = (String::new(), String::new());
+
+ let c = || {
+ println!("{}", t.0);
+ };
+
+ c();
+}
+
+// Test migration analysis in case of Insignificant Drop + Non Drop aggregates.
+// Note in this test the closure captures a non Drop type and therefore the variable
+// is only captured by ref.
+fn test4_insignificant_drop_non_drop_aggregate() {
+ let t = (String::new(), 0i32);
+
+ let c = || {
+ let _t = t.1;
+ };
+
+ c();
+}
+
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+// Test migration analysis in case of Significant Drop + Non Drop aggregates.
+// Note in this test the closure captures a non Drop type and therefore the variable
+// is only captured by ref.
+fn test5_significant_drop_non_drop_aggregate() {
+ let t = (Foo(0), 0i32);
+
+ let c = || {
+ let _t = t.1;
+ };
+
+ c();
+}
+
+fn main() {
+ test1_only_copy_types();
+ test2_only_copy_types_move_closure();
+ test3_only_copy_types_move_closure();
+ test4_insignificant_drop_non_drop_aggregate();
+ test5_significant_drop_non_drop_aggregate();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/old_name.rs b/tests/ui/closures/2229_closure_analysis/migrations/old_name.rs
new file mode 100644
index 000000000..16e3cca7b
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/old_name.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+// Ensure that the old name for `rust_2021_incompatible_closure_captures` is still
+// accepted by the compiler
+
+#![allow(disjoint_capture_migration)]
+//~^ WARN lint `disjoint_capture_migration` has been renamed
+
+fn main() {}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/old_name.stderr b/tests/ui/closures/2229_closure_analysis/migrations/old_name.stderr
new file mode 100644
index 000000000..47cb689fa
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/old_name.stderr
@@ -0,0 +1,10 @@
+warning: lint `disjoint_capture_migration` has been renamed to `rust_2021_incompatible_closure_captures`
+ --> $DIR/old_name.rs:6:10
+ |
+LL | #![allow(disjoint_capture_migration)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `rust_2021_incompatible_closure_captures`
+ |
+ = note: `#[warn(renamed_and_removed_lints)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/precise.fixed b/tests/ui/closures/2229_closure_analysis/migrations/precise.fixed
new file mode 100644
index 000000000..7892a72c7
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/precise.fixed
@@ -0,0 +1,69 @@
+// run-rustfix
+
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE: the lint level is defined here
+
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+struct ConstainsDropField(Foo, Foo);
+
+// Test that lint is triggered if a path that implements Drop is not captured by move
+fn test_precise_analysis_drop_paths_not_captured_by_move() {
+ let t = ConstainsDropField(Foo(10), Foo(20));
+
+ let c = || {
+ let _ = &t;
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t` to be fully captured
+ let _t = t.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+ let _t = &t.1;
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+
+struct S;
+impl Drop for S {
+ fn drop(&mut self) {}
+}
+
+struct T(S, S);
+struct U(T, T);
+
+// Test precise analysis for the lint works with paths longer than one.
+fn test_precise_analysis_long_path_missing() {
+ let u = U(T(S, S), T(S, S));
+
+ let c = || {
+ let _ = &u;
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `u` to be fully captured
+ let _x = u.0.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `u`, but in Rust 2021, it will only capture `u.0.0`
+ let _x = u.0.1;
+ //~^ NOTE: in Rust 2018, this closure captures all of `u`, but in Rust 2021, it will only capture `u.0.1`
+ let _x = u.1.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `u`, but in Rust 2021, it will only capture `u.1.0`
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `u` is dropped here, but in Rust 2021, only `u.0.0` will be dropped here as part of the closure
+//~| NOTE: in Rust 2018, `u` is dropped here, but in Rust 2021, only `u.0.1` will be dropped here as part of the closure
+//~| NOTE: in Rust 2018, `u` is dropped here, but in Rust 2021, only `u.1.0` will be dropped here as part of the closure
+
+
+fn main() {
+ test_precise_analysis_drop_paths_not_captured_by_move();
+ test_precise_analysis_long_path_missing();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/precise.rs b/tests/ui/closures/2229_closure_analysis/migrations/precise.rs
new file mode 100644
index 000000000..f5e99002b
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/precise.rs
@@ -0,0 +1,67 @@
+// run-rustfix
+
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE: the lint level is defined here
+
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+struct ConstainsDropField(Foo, Foo);
+
+// Test that lint is triggered if a path that implements Drop is not captured by move
+fn test_precise_analysis_drop_paths_not_captured_by_move() {
+ let t = ConstainsDropField(Foo(10), Foo(20));
+
+ let c = || {
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t` to be fully captured
+ let _t = t.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+ let _t = &t.1;
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+
+struct S;
+impl Drop for S {
+ fn drop(&mut self) {}
+}
+
+struct T(S, S);
+struct U(T, T);
+
+// Test precise analysis for the lint works with paths longer than one.
+fn test_precise_analysis_long_path_missing() {
+ let u = U(T(S, S), T(S, S));
+
+ let c = || {
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `u` to be fully captured
+ let _x = u.0.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `u`, but in Rust 2021, it will only capture `u.0.0`
+ let _x = u.0.1;
+ //~^ NOTE: in Rust 2018, this closure captures all of `u`, but in Rust 2021, it will only capture `u.0.1`
+ let _x = u.1.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `u`, but in Rust 2021, it will only capture `u.1.0`
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `u` is dropped here, but in Rust 2021, only `u.0.0` will be dropped here as part of the closure
+//~| NOTE: in Rust 2018, `u` is dropped here, but in Rust 2021, only `u.0.1` will be dropped here as part of the closure
+//~| NOTE: in Rust 2018, `u` is dropped here, but in Rust 2021, only `u.1.0` will be dropped here as part of the closure
+
+
+fn main() {
+ test_precise_analysis_drop_paths_not_captured_by_move();
+ test_precise_analysis_long_path_missing();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/precise.stderr b/tests/ui/closures/2229_closure_analysis/migrations/precise.stderr
new file mode 100644
index 000000000..eff26a4d6
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/precise.stderr
@@ -0,0 +1,55 @@
+error: changes to closure capture in Rust 2021 will affect drop order
+ --> $DIR/precise.rs:20:13
+ |
+LL | let c = || {
+ | ^^
+...
+LL | let _t = t.0;
+ | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+...
+LL | }
+ | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+note: the lint level is defined here
+ --> $DIR/precise.rs:3:9
+ |
+LL | #![deny(rust_2021_incompatible_closure_captures)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: add a dummy let to cause `t` to be fully captured
+ |
+LL ~ let c = || {
+LL + let _ = &t;
+ |
+
+error: changes to closure capture in Rust 2021 will affect drop order
+ --> $DIR/precise.rs:45:13
+ |
+LL | let c = || {
+ | ^^
+...
+LL | let _x = u.0.0;
+ | ----- in Rust 2018, this closure captures all of `u`, but in Rust 2021, it will only capture `u.0.0`
+LL |
+LL | let _x = u.0.1;
+ | ----- in Rust 2018, this closure captures all of `u`, but in Rust 2021, it will only capture `u.0.1`
+LL |
+LL | let _x = u.1.0;
+ | ----- in Rust 2018, this closure captures all of `u`, but in Rust 2021, it will only capture `u.1.0`
+...
+LL | }
+ | -
+ | |
+ | in Rust 2018, `u` is dropped here, but in Rust 2021, only `u.0.0` will be dropped here as part of the closure
+ | in Rust 2018, `u` is dropped here, but in Rust 2021, only `u.0.1` will be dropped here as part of the closure
+ | in Rust 2018, `u` is dropped here, but in Rust 2021, only `u.1.0` will be dropped here as part of the closure
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `u` to be fully captured
+ |
+LL ~ let c = || {
+LL + let _ = &u;
+ |
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/precise_no_migrations.rs b/tests/ui/closures/2229_closure_analysis/migrations/precise_no_migrations.rs
new file mode 100644
index 000000000..587d71c40
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/precise_no_migrations.rs
@@ -0,0 +1,104 @@
+// run-pass
+
+#![deny(rust_2021_incompatible_closure_captures)]
+
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+struct ConstainsDropField(Foo, Foo);
+
+// Test that if all paths starting at root variable that implement Drop are captured
+// then it doesn't trigger the lint.
+fn test_precise_analysis_simple_1() {
+ let t = (Foo(10), Foo(20), Foo(30));
+
+ let c = || {
+ let _t = t.0;
+ let _t = t.1;
+ let _t = t.2;
+ };
+
+ c();
+}
+
+// Test that if all paths starting at root variable that implement Drop are captured
+// then it doesn't trigger the lint.
+fn test_precise_analysis_simple_2() {
+ let t = ConstainsDropField(Foo(10), Foo(20));
+
+ let c = || {
+ let _t = t.0;
+ let _t = t.1;
+ };
+
+ c();
+}
+
+#[derive(Debug)]
+struct ContainsAndImplsDrop(Foo);
+impl Drop for ContainsAndImplsDrop {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+// If a path isn't directly captured but requires Drop, then this tests that migrations aren't
+// needed if the a parent to that path is captured.
+fn test_precise_analysis_parent_captured_1() {
+ let t = ConstainsDropField(Foo(10), Foo(20));
+
+ let c = || {
+ let _t = t;
+ };
+
+ c();
+}
+
+// If a path isn't directly captured but requires Drop, then this tests that migrations aren't
+// needed if the a parent to that path is captured.
+fn test_precise_analysis_parent_captured_2() {
+ let t = ContainsAndImplsDrop(Foo(10));
+
+ let c = || {
+ let _t = t;
+ };
+
+ c();
+}
+
+struct S;
+impl Drop for S {
+ fn drop(&mut self) {}
+}
+
+struct T(S, S);
+struct U(T, T);
+
+// Test that if the path is longer than just one element, precise analysis works correctly.
+fn test_precise_analysis_long_path() {
+ let u = U(T(S, S), T(S, S));
+
+ let c = || {
+ let _x = u.0.0;
+ let _x = u.0.1;
+ let _x = u.1.0;
+ let _x = u.1.1;
+ };
+
+ c();
+}
+
+fn main() {
+ test_precise_analysis_simple_1();
+ test_precise_analysis_simple_2();
+
+ test_precise_analysis_parent_captured_1();
+ test_precise_analysis_parent_captured_2();
+
+ test_precise_analysis_long_path();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed b/tests/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed
new file mode 100644
index 000000000..e99dbb5ab
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed
@@ -0,0 +1,229 @@
+// run-rustfix
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE: the lint level is defined here
+
+// Test cases for types that implement a significant drop (user defined)
+
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+#[derive(Debug)]
+struct ConstainsDropField(Foo, #[allow(unused_tuple_struct_fields)] Foo);
+
+// `t` needs Drop because one of its elements needs drop,
+// therefore precise capture might affect drop ordering
+fn test1_all_need_migration() {
+ let t = (Foo(0), Foo(0));
+ let t1 = (Foo(0), Foo(0));
+ let t2 = (Foo(0), Foo(0));
+
+ let c = || {
+ let _ = (&t, &t1, &t2);
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t`, `t1`, `t2` to be fully captured
+ let _t = t.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+ let _t1 = t1.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0`
+ let _t2 = t2.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t2`, but in Rust 2021, it will only capture `t2.0`
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+//~| NOTE: in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
+//~| NOTE: in Rust 2018, `t2` is dropped here, but in Rust 2021, only `t2.0` will be dropped here as part of the closure
+
+// String implements drop and therefore should be migrated.
+// But in this test cases, `t2` is completely captured and when it is dropped won't be affected
+fn test2_only_precise_paths_need_migration() {
+ let t = (Foo(0), Foo(0));
+ let t1 = (Foo(0), Foo(0));
+ let t2 = (Foo(0), Foo(0));
+
+ let c = || {
+ let _ = (&t, &t1);
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t`, `t1` to be fully captured
+ let _t = t.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+ let _t1 = t1.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0`
+ let _t2 = t2;
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+//~| NOTE: in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
+
+// If a variable would've not been captured by value then it would've not been
+// dropped with the closure and therefore doesn't need migration.
+fn test3_only_by_value_need_migration() {
+ let t = (Foo(0), Foo(0));
+ let t1 = (Foo(0), Foo(0));
+ let c = || {
+ let _ = &t;
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t` to be fully captured
+ let _t = t.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+ println!("{:?}", t1.1);
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+
+// The root variable might not implement drop themselves but some path starting
+// at the root variable might implement Drop.
+//
+// If this path isn't captured we need to migrate for the root variable.
+fn test4_type_contains_drop_need_migration() {
+ let t = ConstainsDropField(Foo(0), Foo(0));
+
+ let c = || {
+ let _ = &t;
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t` to be fully captured
+ let _t = t.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+
+// Test migration analysis in case of Drop + Non Drop aggregates.
+// Note we need migration here only because the non-copy (because Drop type) is captured,
+// otherwise we won't need to, since we can get away with just by ref capture in that case.
+fn test5_drop_non_drop_aggregate_need_migration() {
+ let t = (Foo(0), Foo(0), 0i32);
+
+ let c = || {
+ let _ = &t;
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t` to be fully captured
+ let _t = t.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+
+// Test migration analysis in case of Significant and Insignificant Drop aggregates.
+fn test6_significant_insignificant_drop_aggregate_need_migration() {
+ let t = (Foo(0), String::new());
+
+ let c = || {
+ let _ = &t;
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t` to be fully captured
+ let _t = t.1;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.1`
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure
+
+// Since we are using a move closure here, both `t` and `t1` get moved
+// even though they are being used by ref inside the closure.
+fn test7_move_closures_non_copy_types_might_need_migration() {
+ let t = (Foo(0), Foo(0));
+ let t1 = (Foo(0), Foo(0), Foo(0));
+
+ let c = move || {
+ let _ = (&t1, &t);
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t1`, `t` to be fully captured
+ println!("{:?} {:?}", t1.1, t.1);
+ //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.1`
+ //~| NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.1`
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure
+//~| NOTE: in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.1` will be dropped here as part of the closure
+
+
+fn test8_drop_order_and_blocks() {
+ {
+ let tuple =
+ (Foo(0), Foo(1));
+ {
+ let c = || {
+ let _ = &tuple;
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `tuple` to be fully captured
+ tuple.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `tuple`, but in Rust 2021, it will only capture `tuple.0`
+ };
+
+ c();
+ }
+ //~^ NOTE: in Rust 2018, `tuple` is dropped here, but in Rust 2021, only `tuple.0` will be dropped here as part of the closure
+ }
+}
+
+fn test9_drop_order_and_nested_closures() {
+ let tuple =
+ (Foo(0), Foo(1));
+ let b = || {
+ let c = || {
+ let _ = &tuple;
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `tuple` to be fully captured
+ tuple.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `tuple`, but in Rust 2021, it will only capture `tuple.0`
+ };
+
+ c();
+ };
+ //~^ NOTE: in Rust 2018, `tuple` is dropped here, but in Rust 2021, only `tuple.0` will be dropped here as part of the closure
+
+ b();
+}
+
+// Test that we migrate if drop order of Vec<T> would be affected if T is a significant drop type
+fn test10_vec_of_significant_drop_type() {
+
+ let tup = (Foo(0), vec![Foo(3)]);
+
+ let _c = || { let _ = &tup; tup.0 };
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `tup` to be fully captured
+ //~| NOTE: in Rust 2018, this closure captures all of `tup`, but in Rust 2021, it will only capture `tup.0`
+}
+//~^ NOTE: in Rust 2018, `tup` is dropped here, but in Rust 2021, only `tup.0` will be dropped here as part of the closure
+
+fn main() {
+ test1_all_need_migration();
+ test2_only_precise_paths_need_migration();
+ test3_only_by_value_need_migration();
+ test4_type_contains_drop_need_migration();
+ test5_drop_non_drop_aggregate_need_migration();
+ test6_significant_insignificant_drop_aggregate_need_migration();
+ test7_move_closures_non_copy_types_might_need_migration();
+ test8_drop_order_and_blocks();
+ test9_drop_order_and_nested_closures();
+ test10_vec_of_significant_drop_type();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/significant_drop.rs b/tests/ui/closures/2229_closure_analysis/migrations/significant_drop.rs
new file mode 100644
index 000000000..62a984c9e
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/significant_drop.rs
@@ -0,0 +1,220 @@
+// run-rustfix
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE: the lint level is defined here
+
+// Test cases for types that implement a significant drop (user defined)
+
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("{:?} dropped", self.0);
+ }
+}
+
+#[derive(Debug)]
+struct ConstainsDropField(Foo, #[allow(unused_tuple_struct_fields)] Foo);
+
+// `t` needs Drop because one of its elements needs drop,
+// therefore precise capture might affect drop ordering
+fn test1_all_need_migration() {
+ let t = (Foo(0), Foo(0));
+ let t1 = (Foo(0), Foo(0));
+ let t2 = (Foo(0), Foo(0));
+
+ let c = || {
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t`, `t1`, `t2` to be fully captured
+ let _t = t.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+ let _t1 = t1.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0`
+ let _t2 = t2.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t2`, but in Rust 2021, it will only capture `t2.0`
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+//~| NOTE: in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
+//~| NOTE: in Rust 2018, `t2` is dropped here, but in Rust 2021, only `t2.0` will be dropped here as part of the closure
+
+// String implements drop and therefore should be migrated.
+// But in this test cases, `t2` is completely captured and when it is dropped won't be affected
+fn test2_only_precise_paths_need_migration() {
+ let t = (Foo(0), Foo(0));
+ let t1 = (Foo(0), Foo(0));
+ let t2 = (Foo(0), Foo(0));
+
+ let c = || {
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t`, `t1` to be fully captured
+ let _t = t.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+ let _t1 = t1.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0`
+ let _t2 = t2;
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+//~| NOTE: in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
+
+// If a variable would've not been captured by value then it would've not been
+// dropped with the closure and therefore doesn't need migration.
+fn test3_only_by_value_need_migration() {
+ let t = (Foo(0), Foo(0));
+ let t1 = (Foo(0), Foo(0));
+ let c = || {
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t` to be fully captured
+ let _t = t.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+ println!("{:?}", t1.1);
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+
+// The root variable might not implement drop themselves but some path starting
+// at the root variable might implement Drop.
+//
+// If this path isn't captured we need to migrate for the root variable.
+fn test4_type_contains_drop_need_migration() {
+ let t = ConstainsDropField(Foo(0), Foo(0));
+
+ let c = || {
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t` to be fully captured
+ let _t = t.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+
+// Test migration analysis in case of Drop + Non Drop aggregates.
+// Note we need migration here only because the non-copy (because Drop type) is captured,
+// otherwise we won't need to, since we can get away with just by ref capture in that case.
+fn test5_drop_non_drop_aggregate_need_migration() {
+ let t = (Foo(0), Foo(0), 0i32);
+
+ let c = || {
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t` to be fully captured
+ let _t = t.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+
+// Test migration analysis in case of Significant and Insignificant Drop aggregates.
+fn test6_significant_insignificant_drop_aggregate_need_migration() {
+ let t = (Foo(0), String::new());
+
+ let c = || {
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t` to be fully captured
+ let _t = t.1;
+ //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.1`
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure
+
+// Since we are using a move closure here, both `t` and `t1` get moved
+// even though they are being used by ref inside the closure.
+fn test7_move_closures_non_copy_types_might_need_migration() {
+ let t = (Foo(0), Foo(0));
+ let t1 = (Foo(0), Foo(0), Foo(0));
+
+ let c = move || {
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `t1`, `t` to be fully captured
+ println!("{:?} {:?}", t1.1, t.1);
+ //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.1`
+ //~| NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.1`
+ };
+
+ c();
+}
+//~^ NOTE: in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure
+//~| NOTE: in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.1` will be dropped here as part of the closure
+
+
+fn test8_drop_order_and_blocks() {
+ {
+ let tuple =
+ (Foo(0), Foo(1));
+ {
+ let c = || {
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `tuple` to be fully captured
+ tuple.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `tuple`, but in Rust 2021, it will only capture `tuple.0`
+ };
+
+ c();
+ }
+ //~^ NOTE: in Rust 2018, `tuple` is dropped here, but in Rust 2021, only `tuple.0` will be dropped here as part of the closure
+ }
+}
+
+fn test9_drop_order_and_nested_closures() {
+ let tuple =
+ (Foo(0), Foo(1));
+ let b = || {
+ let c = || {
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `tuple` to be fully captured
+ tuple.0;
+ //~^ NOTE: in Rust 2018, this closure captures all of `tuple`, but in Rust 2021, it will only capture `tuple.0`
+ };
+
+ c();
+ };
+ //~^ NOTE: in Rust 2018, `tuple` is dropped here, but in Rust 2021, only `tuple.0` will be dropped here as part of the closure
+
+ b();
+}
+
+// Test that we migrate if drop order of Vec<T> would be affected if T is a significant drop type
+fn test10_vec_of_significant_drop_type() {
+
+ let tup = (Foo(0), vec![Foo(3)]);
+
+ let _c = || tup.0;
+ //~^ ERROR: drop order
+ //~| NOTE: for more information, see
+ //~| HELP: add a dummy let to cause `tup` to be fully captured
+ //~| NOTE: in Rust 2018, this closure captures all of `tup`, but in Rust 2021, it will only capture `tup.0`
+}
+//~^ NOTE: in Rust 2018, `tup` is dropped here, but in Rust 2021, only `tup.0` will be dropped here as part of the closure
+
+fn main() {
+ test1_all_need_migration();
+ test2_only_precise_paths_need_migration();
+ test3_only_by_value_need_migration();
+ test4_type_contains_drop_need_migration();
+ test5_drop_non_drop_aggregate_need_migration();
+ test6_significant_insignificant_drop_aggregate_need_migration();
+ test7_move_closures_non_copy_types_might_need_migration();
+ test8_drop_order_and_blocks();
+ test9_drop_order_and_nested_closures();
+ test10_vec_of_significant_drop_type();
+}
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr b/tests/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr
new file mode 100644
index 000000000..54ad20f89
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr
@@ -0,0 +1,214 @@
+error: changes to closure capture in Rust 2021 will affect drop order
+ --> $DIR/significant_drop.rs:25:13
+ |
+LL | let c = || {
+ | ^^
+...
+LL | let _t = t.0;
+ | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+LL |
+LL | let _t1 = t1.0;
+ | ---- in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0`
+LL |
+LL | let _t2 = t2.0;
+ | ---- in Rust 2018, this closure captures all of `t2`, but in Rust 2021, it will only capture `t2.0`
+...
+LL | }
+ | -
+ | |
+ | in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+ | in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
+ | in Rust 2018, `t2` is dropped here, but in Rust 2021, only `t2.0` will be dropped here as part of the closure
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+note: the lint level is defined here
+ --> $DIR/significant_drop.rs:2:9
+ |
+LL | #![deny(rust_2021_incompatible_closure_captures)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: add a dummy let to cause `t`, `t1`, `t2` to be fully captured
+ |
+LL ~ let c = || {
+LL + let _ = (&t, &t1, &t2);
+ |
+
+error: changes to closure capture in Rust 2021 will affect drop order
+ --> $DIR/significant_drop.rs:50:13
+ |
+LL | let c = || {
+ | ^^
+...
+LL | let _t = t.0;
+ | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+LL |
+LL | let _t1 = t1.0;
+ | ---- in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0`
+...
+LL | }
+ | -
+ | |
+ | in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+ | in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `t`, `t1` to be fully captured
+ |
+LL ~ let c = || {
+LL + let _ = (&t, &t1);
+ |
+
+error: changes to closure capture in Rust 2021 will affect drop order
+ --> $DIR/significant_drop.rs:71:13
+ |
+LL | let c = || {
+ | ^^
+...
+LL | let _t = t.0;
+ | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+...
+LL | }
+ | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `t` to be fully captured
+ |
+LL ~ let c = || {
+LL + let _ = &t;
+ |
+
+error: changes to closure capture in Rust 2021 will affect drop order
+ --> $DIR/significant_drop.rs:91:13
+ |
+LL | let c = || {
+ | ^^
+...
+LL | let _t = t.0;
+ | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+...
+LL | }
+ | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `t` to be fully captured
+ |
+LL ~ let c = || {
+LL + let _ = &t;
+ |
+
+error: changes to closure capture in Rust 2021 will affect drop order
+ --> $DIR/significant_drop.rs:109:13
+ |
+LL | let c = || {
+ | ^^
+...
+LL | let _t = t.0;
+ | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+...
+LL | }
+ | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `t` to be fully captured
+ |
+LL ~ let c = || {
+LL + let _ = &t;
+ |
+
+error: changes to closure capture in Rust 2021 will affect drop order
+ --> $DIR/significant_drop.rs:125:13
+ |
+LL | let c = || {
+ | ^^
+...
+LL | let _t = t.1;
+ | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.1`
+...
+LL | }
+ | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `t` to be fully captured
+ |
+LL ~ let c = || {
+LL + let _ = &t;
+ |
+
+error: changes to closure capture in Rust 2021 will affect drop order
+ --> $DIR/significant_drop.rs:143:13
+ |
+LL | let c = move || {
+ | ^^^^^^^
+...
+LL | println!("{:?} {:?}", t1.1, t.1);
+ | ---- --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.1`
+ | |
+ | in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.1`
+...
+LL | }
+ | -
+ | |
+ | in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.1` will be dropped here as part of the closure
+ | in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `t1`, `t` to be fully captured
+ |
+LL ~ let c = move || {
+LL + let _ = (&t1, &t);
+ |
+
+error: changes to closure capture in Rust 2021 will affect drop order
+ --> $DIR/significant_drop.rs:163:21
+ |
+LL | let c = || {
+ | ^^
+...
+LL | tuple.0;
+ | ------- in Rust 2018, this closure captures all of `tuple`, but in Rust 2021, it will only capture `tuple.0`
+...
+LL | }
+ | - in Rust 2018, `tuple` is dropped here, but in Rust 2021, only `tuple.0` will be dropped here as part of the closure
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `tuple` to be fully captured
+ |
+LL ~ let c = || {
+LL + let _ = &tuple;
+ |
+
+error: changes to closure capture in Rust 2021 will affect drop order
+ --> $DIR/significant_drop.rs:181:17
+ |
+LL | let c = || {
+ | ^^
+...
+LL | tuple.0;
+ | ------- in Rust 2018, this closure captures all of `tuple`, but in Rust 2021, it will only capture `tuple.0`
+...
+LL | };
+ | - in Rust 2018, `tuple` is dropped here, but in Rust 2021, only `tuple.0` will be dropped here as part of the closure
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `tuple` to be fully captured
+ |
+LL ~ let c = || {
+LL + let _ = &tuple;
+ |
+
+error: changes to closure capture in Rust 2021 will affect drop order
+ --> $DIR/significant_drop.rs:201:18
+ |
+LL | let _c = || tup.0;
+ | ^^ ----- in Rust 2018, this closure captures all of `tup`, but in Rust 2021, it will only capture `tup.0`
+...
+LL | }
+ | - in Rust 2018, `tup` is dropped here, but in Rust 2021, only `tup.0` will be dropped here as part of the closure
+ |
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `tup` to be fully captured
+ |
+LL | let _c = || { let _ = &tup; tup.0 };
+ | +++++++++++++++ +
+
+error: aborting due to 10 previous errors
+
diff --git a/tests/ui/closures/2229_closure_analysis/migrations/unpin_no_migration.rs b/tests/ui/closures/2229_closure_analysis/migrations/unpin_no_migration.rs
new file mode 100644
index 000000000..39cf82053
--- /dev/null
+++ b/tests/ui/closures/2229_closure_analysis/migrations/unpin_no_migration.rs
@@ -0,0 +1,13 @@
+//run-pass
+#![deny(rust_2021_incompatible_closure_captures)]
+#![allow(unused_must_use)]
+
+fn filter_try_fold(
+ predicate: &mut impl FnMut() -> bool,
+) -> impl FnMut() -> bool + '_ {
+ move || predicate()
+}
+
+fn main() {
+ filter_try_fold(&mut || true);
+}