diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 32d271d94c8..98415a84c56 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -3,6 +3,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::Limit; @@ -12,7 +13,7 @@ type NeedsDropResult = Result; fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { let adt_components = - move |adt_def: &ty::AdtDef| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter()); + move |adt_def: &ty::AdtDef, _| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter()); // If we don't know a type doesn't need drop, for example if it's a type // parameter without a `Copy` bound, then we conservatively return that it @@ -28,8 +29,9 @@ fn has_significant_drop_raw<'tcx>( tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, ) -> bool { - let significant_drop_fields = - move |adt_def: &ty::AdtDef| tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter()); + let significant_drop_fields = move |adt_def: &ty::AdtDef, _| { + tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter()) + }; let res = NeedsDropTypes::new(tcx, query.param_env, query.value, significant_drop_fields) .next() .is_some(); @@ -74,7 +76,7 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> { impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F> where - F: Fn(&ty::AdtDef) -> NeedsDropResult, + F: Fn(&ty::AdtDef, SubstsRef<'tcx>) -> NeedsDropResult, I: Iterator>, { type Item = NeedsDropResult>; @@ -138,7 +140,7 @@ where // `ManuallyDrop`. If it's a struct or enum without a `Drop` // impl then check whether the field types need `Drop`. ty::Adt(adt_def, substs) => { - let tys = match (self.adt_components)(adt_def) { + let tys = match (self.adt_components)(adt_def, substs) { Err(e) => return Some(Err(e)), Ok(tys) => tys, }; @@ -171,22 +173,44 @@ where } } +enum DtorType { + /// Type has a `Drop` but it is considered insignificant. + /// Check the query `adt_significant_drop_tys` for understanding + /// "significant" / "insignificant". + Insignificant, + + /// Type has a `Drop` implentation. + Significant, +} + // This is a helper function for `adt_drop_tys` and `adt_significant_drop_tys`. // Depending on the implentation of `adt_has_dtor`, it is used to check if the // ADT has a destructor or if the ADT only has a significant destructor. For // understanding significant destructor look at `adt_significant_drop_tys`. -fn adt_drop_tys_helper( - tcx: TyCtxt<'_>, +fn adt_drop_tys_helper<'tcx>( + tcx: TyCtxt<'tcx>, def_id: DefId, - adt_has_dtor: impl Fn(&ty::AdtDef) -> bool, -) -> Result<&ty::List>, AlwaysRequiresDrop> { - let adt_components = move |adt_def: &ty::AdtDef| { + adt_has_dtor: impl Fn(&ty::AdtDef) -> Option, +) -> Result<&ty::List>, AlwaysRequiresDrop> { + let adt_components = move |adt_def: &ty::AdtDef, substs: SubstsRef<'tcx>| { if adt_def.is_manually_drop() { debug!("adt_drop_tys: `{:?}` is manually drop", adt_def); return Ok(Vec::new().into_iter()); - } else if adt_has_dtor(adt_def) { - debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def); - return Err(AlwaysRequiresDrop); + } else if let Some(dtor_info) = adt_has_dtor(adt_def) { + match dtor_info { + DtorType::Significant => { + debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def); + return Err(AlwaysRequiresDrop); + } + DtorType::Insignificant => { + debug!("adt_drop_tys: `{:?}` drop is insignificant", adt_def); + + // Since the destructor is insignificant, we just want to make sure all of + // the passed in type parameters are also insignificant. + // Eg: Vec dtor is insignificant when T=i32 but significant when T=Mutex. + return Ok(substs.types().collect::>>().into_iter()); + } + } } else if adt_def.is_union() { debug!("adt_drop_tys: `{:?}` is a union", adt_def); return Ok(Vec::new().into_iter()); @@ -204,7 +228,10 @@ fn adt_drop_tys_helper( } fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List>, AlwaysRequiresDrop> { - let adt_has_dtor = |adt_def: &ty::AdtDef| adt_def.destructor(tcx).is_some(); + // This is for the "needs_drop" query, that considers all `Drop` impls, therefore all dtors are + // significant. + let adt_has_dtor = + |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant); adt_drop_tys_helper(tcx, def_id, adt_has_dtor) } @@ -213,10 +240,22 @@ fn adt_significant_drop_tys( def_id: DefId, ) -> Result<&ty::List>, AlwaysRequiresDrop> { let adt_has_dtor = |adt_def: &ty::AdtDef| { - adt_def - .destructor(tcx) - .map(|dtor| !tcx.has_attr(dtor.did, sym::rustc_insignificant_dtor)) - .unwrap_or(false) + let is_marked_insig = tcx.has_attr(adt_def.did, sym::rustc_insignificant_dtor); + if is_marked_insig { + // In some cases like `std::collections::HashMap` where the struct is a wrapper around + // a type that is a Drop type, and the wrapped type (eg: `hashbrown::HashMap`) lies + // outside stdlib, we might choose to still annotate the the wrapper (std HashMap) with + // `rustc_insignificant_dtor`, even if the type itself doesn't have a `Drop` impl. + Some(DtorType::Insignificant) + } else if adt_def.destructor(tcx).is_some() { + // There is a Drop impl and the type isn't marked insignificant, therefore Drop must be + // significant. + Some(DtorType::Significant) + } else { + // No destructor found nor the type is annotated with `rustc_insignificant_dtor`, we + // treat this as the simple case of Drop impl for type. + None + } }; adt_drop_tys_helper(tcx, def_id, adt_has_dtor) } diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 2a7e1ef351b..3b7c92818f6 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -155,6 +155,7 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "BTreeMap")] +#[rustc_insignificant_dtor] pub struct BTreeMap { root: Option>, length: usize, @@ -331,6 +332,7 @@ impl fmt::Debug for IterMut<'_, K, V> { /// [`into_iter`]: IntoIterator::into_iter /// [`IntoIterator`]: core::iter::IntoIterator #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] pub struct IntoIter { range: LazyLeafRange, length: usize, diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 0b60c2aa9f6..a769c558b4f 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -46,6 +46,7 @@ mod tests; /// [`VecDeque`]: super::vec_deque::VecDeque #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "LinkedList")] +#[rustc_insignificant_dtor] pub struct LinkedList { head: Option>>, tail: Option>>, diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 10144cc17bf..cae0f29af83 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -90,6 +90,7 @@ const MAXIMUM_ZST_CAPACITY: usize = 1 << (usize::BITS - 1); // Largest possible /// [`make_contiguous`]: VecDeque::make_contiguous #[cfg_attr(not(test), rustc_diagnostic_item = "vecdeque_type")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] pub struct VecDeque< T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 3648271c620..81e97805a72 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -305,6 +305,7 @@ struct RcBox { /// [get_mut]: Rc::get_mut #[cfg_attr(not(test), rustc_diagnostic_item = "Rc")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] pub struct Rc { ptr: NonNull>, phantom: PhantomData>, diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 0bd152f17a6..4cb0a4b10bd 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -22,6 +22,7 @@ use core::slice::{self}; /// let iter: std::vec::IntoIter<_> = v.into_iter(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] pub struct IntoIter< T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 4440b1f599f..c37ec375561 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -396,6 +396,7 @@ mod spec_extend; /// [owned slice]: Box #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")] +#[rustc_insignificant_dtor] pub struct Vec { buf: RawVec, len: usize, diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index ecdbf098819..822747dd0e8 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -10,6 +10,7 @@ use crate::{ /// A by-value [array] iterator. #[stable(feature = "array_value_iter", since = "1.51.0")] +#[rustc_insignificant_dtor] pub struct IntoIter { /// This is the array we are iterating over. /// diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 862f411ebe0..f96906be540 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -205,6 +205,7 @@ use crate::sys; #[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_type")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] pub struct HashMap { base: base::HashMap, } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed index beebb118399..b0fc5120f08 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed @@ -4,6 +4,14 @@ 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 {} @@ -42,19 +50,19 @@ fn test_sync_trait() { } /* Test Clone Trait Migration */ -struct S(String); +struct S(Foo); struct T(i32); struct U(S, T); impl Clone for U { fn clone(&self) -> Self { - U(S(String::from("Hello World")), T(0)) + U(S(Foo(0)), T(0)) } } fn test_clone_trait() { - let f = U(S(String::from("Hello World")), T(0)); + let f = U(S(Foo(0)), T(0)); let c = || { let _ = &f; //~^ ERROR: `Clone` trait implementation for closure and drop order diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs index 812ecae262f..2bcf9a795ed 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs @@ -4,6 +4,14 @@ 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 {} @@ -42,19 +50,19 @@ fn test_sync_trait() { } /* Test Clone Trait Migration */ -struct S(String); +struct S(Foo); struct T(i32); struct U(S, T); impl Clone for U { fn clone(&self) -> Self { - U(S(String::from("Hello World")), T(0)) + U(S(Foo(0)), T(0)) } } fn test_clone_trait() { - let f = U(S(String::from("Hello World")), T(0)); + let f = U(S(Foo(0)), T(0)); let c = || { //~^ ERROR: `Clone` trait implementation for closure and drop order //~| NOTE: in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr index 98396abb6ff..8d2d3553d40 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr @@ -1,5 +1,5 @@ error: changes to closure capture in Rust 2021 will affect `Send` trait implementation for closure - --> $DIR/auto_traits.rs:14:19 + --> $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` as `fptr.0` does not implement `Send` @@ -24,7 +24,7 @@ LL | *fptr.0 = 20; ... error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure - --> $DIR/auto_traits.rs:34:19 + --> $DIR/auto_traits.rs:42:19 | LL | thread::spawn(move || unsafe { | ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send` @@ -44,7 +44,7 @@ LL | *fptr.0.0 = 20; ... error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order - --> $DIR/auto_traits.rs:58:13 + --> $DIR/auto_traits.rs:66: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` as `f.1` does not implement `Clone` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed index f91454aa211..9a6db588c8b 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed @@ -3,6 +3,14 @@ // 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; @@ -15,11 +23,11 @@ macro_rules! m { } fn main() { - let a = (1.to_string(), 2.to_string()); + let a = (Foo(0), Foo(1)); m!({ let _ = &a; //~^ HELP: add a dummy let x = a.0; - println!("{}", x); + println!("{:?}", x); }); } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs index 5a1026d0433..08cc24b4b3f 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs @@ -3,6 +3,14 @@ // 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; @@ -15,10 +23,10 @@ macro_rules! m { } fn main() { - let a = (1.to_string(), 2.to_string()); + let a = (Foo(0), Foo(1)); m!({ //~^ HELP: add a dummy let x = a.0; - println!("{}", x); + println!("{:?}", x); }); } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr index e6e5598f6d2..a2a9da5f87c 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr @@ -1,5 +1,5 @@ warning: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/closure-body-macro-fragment.rs:8:17 + --> $DIR/closure-body-macro-fragment.rs:16:17 | LL | let f = || $body; | _________________^ @@ -15,7 +15,7 @@ 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 | | println!("{:?}", x); LL | | }); | |_______- in this macro invocation | diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed index c82bc369f43..2652bf5988e 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed @@ -1,169 +1,38 @@ +// run-pass // run-rustfix #![deny(rust_2021_incompatible_closure_captures)] -//~^ NOTE: the lint level is defined here +#![allow(unused)] // Test cases for types that implement an insignificant drop (stlib defined) -// `t` needs Drop because one of its elements needs drop, -// therefore precise capture might affect drop ordering -fn test1_all_need_migration() { - let t = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - let t2 = (String::new(), String::new()); +macro_rules! test_insig_dtor_for_type { + ($t: ty, $disambiguator: ident) => { + mod $disambiguator { + use std::collections::*; + use std::rc::Rc; + use std::sync::Mutex; - 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 + fn test_for_type(t: $t) { + let tup = (Mutex::new(0), t); - 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` + let _c = || tup.0; + } + } }; - - c(); } -//~^ 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 -// 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 = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - let t2 = (String::new(), String::new()); +test_insig_dtor_for_type!(i32, prim_i32); +test_insig_dtor_for_type!(Vec, vec_i32); +test_insig_dtor_for_type!(String, string); +test_insig_dtor_for_type!(Vec, vec_string); +test_insig_dtor_for_type!(HashMap, hash_map); +test_insig_dtor_for_type!(BTreeMap, btree_map); +test_insig_dtor_for_type!(LinkedList, linked_list); +test_insig_dtor_for_type!(Rc, rc_i32); +test_insig_dtor_for_type!(Rc, rc_string); +test_insig_dtor_for_type!(std::vec::IntoIter, vec_into_iter); +test_insig_dtor_for_type!(btree_map::IntoIter, btree_map_into_iter); +test_insig_dtor_for_type!(std::array::IntoIter, array_into_iter); - 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(); -} -//~^ 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 - -// 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 = (String::new(), String::new()); - let t1 = (String::new(), 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.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(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - -// Copy types get copied into the closure instead of move. Therefore we don't need to -// migrate then as their drop order isn't tied to the closure. -fn test4_only_non_copy_types_need_migration() { - let t = (String::new(), String::new()); - - // `t1` is Copy because all of its elements are Copy - let t1 = (0i32, 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` - let _t1 = t1.0; - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - -fn test5_only_drop_types_need_migration() { - struct S(i32, i32); - - let t = (String::new(), String::new()); - - // `s` doesn't implement Drop or any elements within it, and doesn't need migration - let s = S(0i32, 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` - let _s = s.0; - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` 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 test6_move_closures_non_copy_types_might_need_migration() { - let t = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - 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 `t`, but in Rust 2021, it will only capture `t.1` - //~| NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.1` - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure -//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.1` 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 test7_drop_non_drop_aggregate_need_migration() { - let t = (String::new(), String::new(), 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(); -} -//~^ 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() { - test1_all_need_migration(); - test2_only_precise_paths_need_migration(); - test3_only_by_value_need_migration(); - test4_only_non_copy_types_need_migration(); - test5_only_drop_types_need_migration(); - test6_move_closures_non_copy_types_might_need_migration(); - test7_drop_non_drop_aggregate_need_migration(); -} +fn main() {} diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs index 57ab15ae8f2..2652bf5988e 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs @@ -1,162 +1,38 @@ +// run-pass // run-rustfix #![deny(rust_2021_incompatible_closure_captures)] -//~^ NOTE: the lint level is defined here +#![allow(unused)] // Test cases for types that implement an insignificant drop (stlib defined) -// `t` needs Drop because one of its elements needs drop, -// therefore precise capture might affect drop ordering -fn test1_all_need_migration() { - let t = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - let t2 = (String::new(), String::new()); +macro_rules! test_insig_dtor_for_type { + ($t: ty, $disambiguator: ident) => { + mod $disambiguator { + use std::collections::*; + use std::rc::Rc; + use std::sync::Mutex; - let c = || { - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t`, `t1`, `t2` to be fully captured + fn test_for_type(t: $t) { + let tup = (Mutex::new(0), t); - 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` + let _c = || tup.0; + } + } }; - - c(); } -//~^ 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 -// 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 = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - let t2 = (String::new(), String::new()); +test_insig_dtor_for_type!(i32, prim_i32); +test_insig_dtor_for_type!(Vec, vec_i32); +test_insig_dtor_for_type!(String, string); +test_insig_dtor_for_type!(Vec, vec_string); +test_insig_dtor_for_type!(HashMap, hash_map); +test_insig_dtor_for_type!(BTreeMap, btree_map); +test_insig_dtor_for_type!(LinkedList, linked_list); +test_insig_dtor_for_type!(Rc, rc_i32); +test_insig_dtor_for_type!(Rc, rc_string); +test_insig_dtor_for_type!(std::vec::IntoIter, vec_into_iter); +test_insig_dtor_for_type!(btree_map::IntoIter, btree_map_into_iter); +test_insig_dtor_for_type!(std::array::IntoIter, array_into_iter); - 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(); -} -//~^ 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 - -// 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 = (String::new(), String::new()); - let t1 = (String::new(), 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.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(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - -// Copy types get copied into the closure instead of move. Therefore we don't need to -// migrate then as their drop order isn't tied to the closure. -fn test4_only_non_copy_types_need_migration() { - let t = (String::new(), String::new()); - - // `t1` is Copy because all of its elements are Copy - let t1 = (0i32, 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` - let _t1 = t1.0; - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - -fn test5_only_drop_types_need_migration() { - struct S(i32, i32); - - let t = (String::new(), String::new()); - - // `s` doesn't implement Drop or any elements within it, and doesn't need migration - let s = S(0i32, 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` - let _s = s.0; - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` 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 test6_move_closures_non_copy_types_might_need_migration() { - let t = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - 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 `t`, but in Rust 2021, it will only capture `t.1` - //~| NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.1` - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure -//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.1` 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 test7_drop_non_drop_aggregate_need_migration() { - let t = (String::new(), String::new(), 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(); -} -//~^ 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() { - test1_all_need_migration(); - test2_only_precise_paths_need_migration(); - test3_only_by_value_need_migration(); - test4_only_non_copy_types_need_migration(); - test5_only_drop_types_need_migration(); - test6_move_closures_non_copy_types_might_need_migration(); - test7_drop_non_drop_aggregate_need_migration(); -} +fn main() {} diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr deleted file mode 100644 index 7989a8fa5cc..00000000000 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr +++ /dev/null @@ -1,161 +0,0 @@ -error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop.rs:15: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: the lint level is defined here - --> $DIR/insignificant_drop.rs:3:9 - | -LL | #![deny(rust_2021_incompatible_closure_captures)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: for more information, see -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/insignificant_drop.rs:41: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 -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/insignificant_drop.rs:62: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 -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.rs:83: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 -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.rs:104: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 -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.rs:122: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 -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/insignificant_drop.rs:142: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 -help: add a dummy let to cause `t` to be fully captured - | -LL ~ let c = || { -LL + let _ = &t; - | - -error: aborting due to 7 previous errors - diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed index e672d9266fc..d985e3bb9ec 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed @@ -5,13 +5,15 @@ #![feature(rustc_attrs)] #![allow(unused)] +use std::sync::Mutex; + + #[rustc_insignificant_dtor] struct InsignificantDropPoint { x: i32, - y: i32, + y: Mutex, } impl Drop for InsignificantDropPoint { - #[rustc_insignificant_dtor] fn drop(&mut self) {} } @@ -21,15 +23,15 @@ impl Drop for SigDrop { fn drop(&mut self) {} } +#[rustc_insignificant_dtor] struct GenericStruct(T, T); -struct Wrapper(GenericStruct, i32); - impl Drop for GenericStruct { - #[rustc_insignificant_dtor] fn drop(&mut self) {} } +struct Wrapper(GenericStruct, i32); + // `SigDrop` implements drop and therefore needs to be migrated. fn significant_drop_needs_migration() { let t = (SigDrop {}, SigDrop {}); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs index 45850ec5f36..f95d34eeb29 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs @@ -5,13 +5,15 @@ #![feature(rustc_attrs)] #![allow(unused)] +use std::sync::Mutex; + + #[rustc_insignificant_dtor] struct InsignificantDropPoint { x: i32, - y: i32, + y: Mutex, } impl Drop for InsignificantDropPoint { - #[rustc_insignificant_dtor] fn drop(&mut self) {} } @@ -21,15 +23,15 @@ impl Drop for SigDrop { fn drop(&mut self) {} } +#[rustc_insignificant_dtor] struct GenericStruct(T, T); -struct Wrapper(GenericStruct, i32); - impl Drop for GenericStruct { - #[rustc_insignificant_dtor] fn drop(&mut self) {} } +struct Wrapper(GenericStruct, i32); + // `SigDrop` implements drop and therefore needs to be migrated. fn significant_drop_needs_migration() { let t = (SigDrop {}, SigDrop {}); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr index 961834aca19..832a81711b1 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr @@ -1,5 +1,5 @@ error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop_attr_migrations.rs:37:13 + --> $DIR/insignificant_drop_attr_migrations.rs:39:13 | LL | let c = || { | ^^ @@ -23,7 +23,7 @@ LL + let _ = &t; | error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop_attr_migrations.rs:57:13 + --> $DIR/insignificant_drop_attr_migrations.rs:59:13 | LL | let c = move || { | ^^^^^^^ diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs index a527bf42e57..3f184a67fba 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs @@ -3,6 +3,7 @@ #![deny(rust_2021_incompatible_closure_captures)] #![feature(rustc_attrs)] #![allow(unused)] +#[rustc_insignificant_dtor] struct InsignificantDropPoint { x: i32, @@ -10,7 +11,6 @@ struct InsignificantDropPoint { } impl Drop for InsignificantDropPoint { - #[rustc_insignificant_dtor] fn drop(&mut self) {} } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/macro.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/macro.fixed index b9dd8a20b09..31fe494dc79 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/macro.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/macro.fixed @@ -5,8 +5,17 @@ #![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 = ("hey".to_string(), "123".to_string()); + let a = (Foo(0), Foo(1)); let _ = || { let _ = &a; dbg!(a.0) }; //~^ ERROR: drop order //~| NOTE: will only capture `a.0` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/macro.rs b/src/test/ui/closures/2229_closure_analysis/migrations/macro.rs index f7ccdb754b8..0f0c4974922 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/macro.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/macro.rs @@ -5,8 +5,17 @@ #![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 = ("hey".to_string(), "123".to_string()); + let a = (Foo(0), Foo(1)); let _ = || dbg!(a.0); //~^ ERROR: drop order //~| NOTE: will only capture `a.0` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr index d1f959dfc52..5046a4bcbb4 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr @@ -1,5 +1,5 @@ error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/macro.rs:10:13 + --> $DIR/macro.rs:19:13 | LL | let _ = || dbg!(a.0); | ^^^^^^^^---^ diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed index ef90257474a..11218eff133 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed @@ -4,7 +4,22 @@ use std::thread; -struct S(String); +#[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(Foo); #[derive(Clone)] struct T(i32); @@ -13,13 +28,13 @@ struct U(S, T); impl Clone for U { fn clone(&self) -> Self { - U(S(String::from("Hello World")), T(0)) + U(S(Foo::from("Hello World")), T(0)) } } fn test_multi_issues() { - let f1 = U(S(String::from("foo")), T(0)); - let f2 = U(S(String::from("bar")), T(0)); + let f1 = U(S(Foo::from("foo")), T(0)); + let f2 = U(S(Foo::from("bar")), T(0)); let c = || { let _ = (&f1, &f2); //~^ ERROR: `Clone` trait implementation for closure and drop order @@ -39,7 +54,7 @@ fn test_multi_issues() { //~^ 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(String::from("foo")), T(0)); + let f1 = U(S(Foo::from("foo")), T(0)); let c = || { let _ = &f1; //~^ ERROR: `Clone` trait implementation for closure @@ -60,12 +75,12 @@ struct U1(S, T, S); impl Clone for U1 { fn clone(&self) -> Self { - U1(S(String::from("foo")), T(0), S(String::from("bar"))) + U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))) } } fn test_capturing_several_disjoint_fields_individually_1() { - let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar"))); + let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { let _ = &f1; //~^ ERROR: `Clone` trait implementation for closure @@ -85,7 +100,7 @@ fn test_capturing_several_disjoint_fields_individually_1() { } fn test_capturing_several_disjoint_fields_individually_2() { - let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar"))); + let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { let _ = &f1; //~^ ERROR: `Clone` trait implementation for closure and drop order diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs index b9644c18d28..02f2faa2e87 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs @@ -4,7 +4,22 @@ use std::thread; -struct S(String); +#[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(Foo); #[derive(Clone)] struct T(i32); @@ -13,13 +28,13 @@ struct U(S, T); impl Clone for U { fn clone(&self) -> Self { - U(S(String::from("Hello World")), T(0)) + U(S(Foo::from("Hello World")), T(0)) } } fn test_multi_issues() { - let f1 = U(S(String::from("foo")), T(0)); - let f2 = U(S(String::from("bar")), T(0)); + let f1 = U(S(Foo::from("foo")), T(0)); + let f2 = U(S(Foo::from("bar")), T(0)); let c = || { //~^ ERROR: `Clone` trait implementation for closure and drop order //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` @@ -38,7 +53,7 @@ fn test_multi_issues() { //~^ 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(String::from("foo")), T(0)); + let f1 = U(S(Foo::from("foo")), T(0)); let c = || { //~^ ERROR: `Clone` trait implementation for closure //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` @@ -58,12 +73,12 @@ struct U1(S, T, S); impl Clone for U1 { fn clone(&self) -> Self { - U1(S(String::from("foo")), T(0), S(String::from("bar"))) + U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))) } } fn test_capturing_several_disjoint_fields_individually_1() { - let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar"))); + let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { //~^ ERROR: `Clone` trait implementation for closure //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` @@ -82,7 +97,7 @@ fn test_capturing_several_disjoint_fields_individually_1() { } fn test_capturing_several_disjoint_fields_individually_2() { - let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar"))); + let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { //~^ ERROR: `Clone` trait implementation for closure and drop order //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr index 8bee950c13e..d425db5aa99 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr @@ -1,5 +1,5 @@ error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order - --> $DIR/multi_diagnostics.rs:23:13 + --> $DIR/multi_diagnostics.rs:38: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` as `f1.0` does not implement `Clone` @@ -26,7 +26,7 @@ LL + let _ = (&f1, &f2); | error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure - --> $DIR/multi_diagnostics.rs:42:13 + --> $DIR/multi_diagnostics.rs:57: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` as `f1.0` does not implement `Clone` @@ -42,7 +42,7 @@ LL + let _ = &f1; | error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure - --> $DIR/multi_diagnostics.rs:67:13 + --> $DIR/multi_diagnostics.rs:82:13 | LL | let c = || { | ^^ @@ -64,7 +64,7 @@ LL + let _ = &f1; | error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order - --> $DIR/multi_diagnostics.rs:86:13 + --> $DIR/multi_diagnostics.rs:101: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` as `f1.0` does not implement `Clone` @@ -89,7 +89,7 @@ LL + let _ = &f1; | error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure - --> $DIR/multi_diagnostics.rs:119:19 + --> $DIR/multi_diagnostics.rs:134:19 | LL | thread::spawn(move || unsafe { | ^^^^^^^^^^^^^^ diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed index aca0b2a96ac..63e4000e833 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed @@ -165,7 +165,7 @@ fn test7_move_closures_non_copy_types_might_need_migration() { fn test8_drop_order_and_blocks() { { let tuple = - (String::from("foo"), String::from("bar")); + (Foo(0), Foo(1)); { let c = || { let _ = &tuple; @@ -184,7 +184,7 @@ fn test8_drop_order_and_blocks() { fn test9_drop_order_and_nested_closures() { let tuple = - (String::from("foo"), String::from("bar")); + (Foo(0), Foo(1)); let b = || { let c = || { let _ = &tuple; @@ -202,6 +202,19 @@ fn test9_drop_order_and_nested_closures() { b(); } +// Test that we migrate if drop order of Vec 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(); @@ -212,4 +225,5 @@ fn main() { 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/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs index fd4134a7704..9d9c54298cf 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs @@ -158,7 +158,7 @@ fn test7_move_closures_non_copy_types_might_need_migration() { fn test8_drop_order_and_blocks() { { let tuple = - (String::from("foo"), String::from("bar")); + (Foo(0), Foo(1)); { let c = || { //~^ ERROR: drop order @@ -176,7 +176,7 @@ fn test8_drop_order_and_blocks() { fn test9_drop_order_and_nested_closures() { let tuple = - (String::from("foo"), String::from("bar")); + (Foo(0), Foo(1)); let b = || { let c = || { //~^ ERROR: drop order @@ -193,6 +193,19 @@ fn test9_drop_order_and_nested_closures() { b(); } +// Test that we migrate if drop order of Vec 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(); @@ -203,4 +216,5 @@ fn main() { 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/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr index e9170eba3f1..fa1f83c3782 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr @@ -195,5 +195,22 @@ LL ~ let c = || { LL + let _ = &tuple; | -error: aborting due to 9 previous errors +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 +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