]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #89144 - sexxi-goose:insig_stdlib, r=nikomatsakis
authorbors <bors@rust-lang.org>
Sun, 26 Sep 2021 19:36:00 +0000 (19:36 +0000)
committerbors <bors@rust-lang.org>
Sun, 26 Sep 2021 19:36:00 +0000 (19:36 +0000)
2229: Mark insignificant dtor in stdlib

I looked at all public [stdlib Drop implementations](https://doc.rust-lang.org/stable/std/ops/trait.Drop.html#implementors) and categorized them into Insigificant/Maybe/Significant Drop.

Reasons are noted here: https://docs.google.com/spreadsheets/d/19edb9r5lo2UqMrCOVjV0fwcSdS-R7qvKNL76q7tO8VA/edit#gid=1838773501

One thing missing from this PR is tagging HashMap as insigificant destructor as that needs some discussion.

r? `@Mark-Simulacrum`

cc `@nikomatsakis`

31 files changed:
compiler/rustc_ty_utils/src/needs_drop.rs
library/alloc/src/collections/btree/map.rs
library/alloc/src/collections/linked_list.rs
library/alloc/src/collections/vec_deque/mod.rs
library/alloc/src/rc.rs
library/alloc/src/vec/into_iter.rs
library/alloc/src/vec/mod.rs
library/core/src/array/iter.rs
library/std/src/collections/hash/map.rs
src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed
src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs
src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr
src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed
src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs
src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr
src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed
src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs
src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr [deleted file]
src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed
src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs
src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr
src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs
src/test/ui/closures/2229_closure_analysis/migrations/macro.fixed
src/test/ui/closures/2229_closure_analysis/migrations/macro.rs
src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr
src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed
src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs
src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr
src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed
src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs
src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr

index 32d271d94c8ea2ac79984c2fc5b7562237191e12..98415a84c569bc0191dadf2bf06e08f7788a5dae 100644 (file)
@@ -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 @@
 
 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 @@ fn new(
 
 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>>;
@@ -138,7 +140,7 @@ fn next(&mut self) -> Option<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,
                         };
@@ -171,22 +173,44 @@ fn next(&mut self) -> Option<NeedsDropResult<Ty<'tcx>>> {
     }
 }
 
+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());
@@ -204,7 +228,10 @@ fn adt_drop_tys_helper(
 }
 
 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)
 }
 
@@ -213,10 +240,22 @@ fn adt_significant_drop_tys(
     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)
 }
index 2a7e1ef351bc6d6887567b9e056942696809c198..3b7c92818f698facd8ae4aea9d7a12f182f80b6e 100644 (file)
 /// ```
 #[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,
@@ -331,6 +332,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// [`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,
index 0b60c2aa9f66a6e53fe48e98fd300988f32c6cbb..a769c558b4fa90f39e7e8ed344c677ae718edc6b 100644 (file)
@@ -46,6 +46,7 @@
 /// [`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>>>,
index 10144cc17bf306579ccc1b4e2272fb86b11a644d..cae0f29af8327e4340438426dd50b28b9373542f 100644 (file)
@@ -90,6 +90,7 @@
 /// [`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,
index 3648271c6205b6832259fb47ae636f008c9bc2bc..81e97805a72142a65408b0ebba48e6ad3214bc75 100644 (file)
@@ -305,6 +305,7 @@ struct RcBox<T: ?Sized> {
 /// [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>>,
index 0bd152f17a670e2afa3b4180b812400e1c4865ee..4cb0a4b10bd0cdde6f10816f4af69a19fde12db0 100644 (file)
@@ -22,6 +22,7 @@
 /// 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,
index 4440b1f599f76862321a8b7d11fbe86e7d6c61d9..c37ec37556157648b9986598487b396c1b709130 100644 (file)
 /// [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,
index ecdbf09881985a9ee7e4ab997c3750994a6142cd..822747dd0e824ff81736c980325824d278b146ce 100644 (file)
@@ -10,6 +10,7 @@
 
 /// 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.
     ///
index 862f411ebe058e8e42ae2b0bf88db34cdaea3a14..f96906be540f99e0abd30348f9835f46f619d10e 100644 (file)
 
 #[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>,
 }
index beebb118399f3920f0b04fbc154be73ae751108a..b0fc5120f08f219783461c3e3e44316ed4323b28 100644 (file)
@@ -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
index 812ecae262f77b8b2ee74d99024aec6fc021fa2f..2bcf9a795edbd8f9fa093efe8b216d76725d777f 100644 (file)
@@ -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`
index 98396abb6ff66d6f11cd3c5a3d3a331e01709899..8d2d3553d4040f2fdbb6027cbe71d5fb5c3fd700 100644 (file)
@@ -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`
index f91454aa2111e044ee11a99f84582a8b02e267de..9a6db588c8bf50f8b9138af373678202242ea632 100644 (file)
@@ -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);
     });
 }
index 5a1026d04331912d4d998eea56b7bacfd7da06a9..08cc24b4b3fe8f173c066d9a2d481e0c7fe463ff 100644 (file)
@@ -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);
     });
 }
index e6e5598f6d2a1beee09d78c72271ab1c511f074b..a2a9da5f87ced2f9ed3f24fe9ee3cfc45670c485 100644 (file)
@@ -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
    |
index c82bc369f430181f594aa0a38f2356b521dfcd2d..2652bf5988e6543472052504c1183f753641be80 100644 (file)
+// 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() {}
index 57ab15ae8f2439041e440060209a480df4cd4457..2652bf5988e6543472052504c1183f753641be80 100644 (file)
+// 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() {}
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 (file)
index 7989a8f..0000000
+++ /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 <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
-
index e672d9266fcd19dba7135009d4e73e3111528304..d985e3bb9ec74131ff59a13d678b0bbdfdf9ea12 100644 (file)
@@ -5,13 +5,15 @@
 #![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) {}
 }
 
@@ -21,15 +23,15 @@ impl Drop for SigDrop {
     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 {});
index 45850ec5f36dce9f68e8ee665e29456bea5a641e..f95d34eeb299aaf68d60392aae52bf0cac006226 100644 (file)
@@ -5,13 +5,15 @@
 #![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) {}
 }
 
@@ -21,15 +23,15 @@ impl Drop for SigDrop {
     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 {});
index 961834aca194d4b2daef9f515bae695f76a66fc7..832a81711b13775a1f6f516b708ad1ba24b6a77d 100644 (file)
@@ -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 || {
    |             ^^^^^^^
index a527bf42e574a7b8ce1ccf6140980854ba9e8210..3f184a67fbac93b728fac5ccce07a6a4500cf71f 100644 (file)
@@ -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) {}
 }
 
index b9dd8a20b093f782ebb7c5962a331371bb7e1599..31fe494dc795a900620a2ac511adf7963e342b36 100644 (file)
@@ -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`
index f7ccdb754b85821acbcad57dc77948346dc1af44..0f0c497492290b60fd769e64328d98d686c77970 100644 (file)
@@ -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`
index d1f959dfc520e2fe8f5f5e2965c2ff4670f26c1a..5046a4bcbb4b37fa009b59c965cc11eb93ecbc36 100644 (file)
@@ -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);
    |             ^^^^^^^^---^
index ef90257474a9f78eb9da9e65d5b1823fa8ff5ead..11218eff1337f7f63e779df6b9ec5a7a40fdc429 100644 (file)
@@ -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
index b9644c18d28e28465ee5a40e3de4eefa1318c0f8..02f2faa2e8741615266e5f91687be7713335d207 100644 (file)
@@ -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);
 
 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 @@ fn test_capturing_all_disjoint_fields_individually() {
 
 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`
index 8bee950c13eca0273b93632434119816ad03661c..d425db5aa998c69394a674441809eef0581660b3 100644 (file)
@@ -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 {
    |                   ^^^^^^^^^^^^^^
index aca0b2a96ac56bc2b6a6cc5fdb2ec0b73a474222..63e4000e833eb584424d8d52fec54b0f638d0906 100644 (file)
@@ -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<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();
@@ -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();
 }
index fd4134a7704793daacf70bf73b243ee027b0a782..9d9c54298cf112ccb9c838a934fe33320380fa46 100644 (file)
@@ -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<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();
@@ -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();
 }
index e9170eba3f17665f3855d65e8c389f1c5516996e..fa1f83c37823f5e55f356904f81201cbef636ea6 100644 (file)
@@ -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 <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