diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:13 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:13 +0000 |
commit | 218caa410aa38c29984be31a5229b9fa717560ee (patch) | |
tree | c54bd55eeb6e4c508940a30e94c0032fbd45d677 /tests/ui/closures/2229_closure_analysis/migrations | |
parent | Releasing progress-linux version 1.67.1+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-218caa410aa38c29984be31a5229b9fa717560ee.tar.xz rustc-218caa410aa38c29984be31a5229b9fa717560ee.zip |
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/ui/closures/2229_closure_analysis/migrations')
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); +} |