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;
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
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();
impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F>
where
- F: Fn(&ty::AdtDef) -> NeedsDropResult<I>,
+ F: Fn(&ty::AdtDef, SubstsRef<'tcx>) -> NeedsDropResult<I>,
I: Iterator<Item = Ty<'tcx>>,
{
type Item = NeedsDropResult<Ty<'tcx>>;
// `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,
};
}
}
+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<Ty<'_>>, AlwaysRequiresDrop> {
- let adt_components = move |adt_def: &ty::AdtDef| {
+ adt_has_dtor: impl Fn(&ty::AdtDef) -> Option<DtorType>,
+) -> Result<&ty::List<Ty<'tcx>>, 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<T> dtor is insignificant when T=i32 but significant when T=Mutex.
+ return Ok(substs.types().collect::<Vec<Ty<'_>>>().into_iter());
+ }
+ }
} else if adt_def.is_union() {
debug!("adt_drop_tys: `{:?}` is a union", adt_def);
return Ok(Vec::new().into_iter());
}
fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, 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)
}
def_id: DefId,
) -> Result<&ty::List<Ty<'_>>, 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)
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "BTreeMap")]
+#[rustc_insignificant_dtor]
pub struct BTreeMap<K, V> {
root: Option<Root<K, V>>,
length: usize,
/// [`into_iter`]: IntoIterator::into_iter
/// [`IntoIterator`]: core::iter::IntoIterator
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
pub struct IntoIter<K, V> {
range: LazyLeafRange<marker::Dying, K, V>,
length: usize,
/// [`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<T> {
head: Option<NonNull<Node<T>>>,
tail: Option<NonNull<Node<T>>>,
/// [`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,
/// [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<T: ?Sized> {
ptr: NonNull<RcBox<T>>,
phantom: PhantomData<RcBox<T>>,
/// 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,
/// [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<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
buf: RawVec<T, A>,
len: usize,
/// A by-value [array] iterator.
#[stable(feature = "array_value_iter", since = "1.51.0")]
+#[rustc_insignificant_dtor]
pub struct IntoIter<T, const N: usize> {
/// This is the array we are iterating over.
///
#[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_type")]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
pub struct HashMap<K, V, S = RandomState> {
base: base::HashMap<K, V, S>,
}
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 {}
}
/* 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
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 {}
}
/* 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`
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`
...
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`
...
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`
// 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;
}
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);
});
}
// 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;
}
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);
});
}
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;
| _________________^
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
|
+// 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());
-
- 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();
-}
+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() {}
+// 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());
-
- 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();
-}
+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() {}
+++ /dev/null
-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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
-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 <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/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 <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/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 <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/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 <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/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 <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/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 <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: aborting due to 7 previous errors
-
#![feature(rustc_attrs)]
#![allow(unused)]
+use std::sync::Mutex;
+
+ #[rustc_insignificant_dtor]
struct InsignificantDropPoint {
x: i32,
- y: i32,
+ y: Mutex<i32>,
}
impl Drop for InsignificantDropPoint {
- #[rustc_insignificant_dtor]
fn drop(&mut self) {}
}
fn drop(&mut self) {}
}
+#[rustc_insignificant_dtor]
struct GenericStruct<T>(T, T);
-struct Wrapper<T>(GenericStruct<T>, i32);
-
impl<T> Drop for GenericStruct<T> {
- #[rustc_insignificant_dtor]
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 {});
#![feature(rustc_attrs)]
#![allow(unused)]
+use std::sync::Mutex;
+
+ #[rustc_insignificant_dtor]
struct InsignificantDropPoint {
x: i32,
- y: i32,
+ y: Mutex<i32>,
}
impl Drop for InsignificantDropPoint {
- #[rustc_insignificant_dtor]
fn drop(&mut self) {}
}
fn drop(&mut self) {}
}
+#[rustc_insignificant_dtor]
struct GenericStruct<T>(T, T);
-struct Wrapper<T>(GenericStruct<T>, i32);
-
impl<T> Drop for GenericStruct<T> {
- #[rustc_insignificant_dtor]
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 {});
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 = || {
| ^^
|
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 || {
| ^^^^^^^
#![deny(rust_2021_incompatible_closure_captures)]
#![feature(rustc_attrs)]
#![allow(unused)]
+#[rustc_insignificant_dtor]
struct InsignificantDropPoint {
x: i32,
}
impl Drop for InsignificantDropPoint {
- #[rustc_insignificant_dtor]
fn drop(&mut self) {}
}
#![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`
#![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`
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);
| ^^^^^^^^---^
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);
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
//~^ 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
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
}
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
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);
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`
//~^ 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`
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`
}
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`
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`
|
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`
|
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 = || {
| ^^
|
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`
|
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 {
| ^^^^^^^^^^^^^^
fn test8_drop_order_and_blocks() {
{
let tuple =
- (String::from("foo"), String::from("bar"));
+ (Foo(0), Foo(1));
{
let c = || {
let _ = &tuple;
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;
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();
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();
}
fn test8_drop_order_and_blocks() {
{
let tuple =
- (String::from("foo"), String::from("bar"));
+ (Foo(0), Foo(1));
{
let c = || {
//~^ ERROR: drop order
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
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();
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();
}
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 <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