about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ty_utils/src/needs_drop.rs75
-rw-r--r--library/alloc/src/collections/btree/map.rs2
-rw-r--r--library/alloc/src/collections/linked_list.rs1
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs1
-rw-r--r--library/alloc/src/rc.rs1
-rw-r--r--library/alloc/src/vec/into_iter.rs1
-rw-r--r--library/alloc/src/vec/mod.rs1
-rw-r--r--library/core/src/array/iter.rs1
-rw-r--r--library/std/src/collections/hash/map.rs1
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed14
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs14
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr6
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed12
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs12
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr4
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed185
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs178
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr161
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed12
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs12
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr4
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs2
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/macro.fixed11
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/macro.rs11
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr2
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed31
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs31
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr10
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed18
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs18
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr19
31 files changed, 306 insertions, 545 deletions
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index 32d271d94c8..98415a84c56 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -3,6 +3,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::Limit;
@@ -12,7 +13,7 @@ type NeedsDropResult<T> = Result<T, AlwaysRequiresDrop>;
 
 fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
     let adt_components =
-        move |adt_def: &ty::AdtDef| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter());
+        move |adt_def: &ty::AdtDef, _| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter());
 
     // If we don't know a type doesn't need drop, for example if it's a type
     // parameter without a `Copy` bound, then we conservatively return that it
@@ -28,8 +29,9 @@ fn has_significant_drop_raw<'tcx>(
     tcx: TyCtxt<'tcx>,
     query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
 ) -> bool {
-    let significant_drop_fields =
-        move |adt_def: &ty::AdtDef| tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter());
+    let significant_drop_fields = move |adt_def: &ty::AdtDef, _| {
+        tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter())
+    };
     let res = NeedsDropTypes::new(tcx, query.param_env, query.value, significant_drop_fields)
         .next()
         .is_some();
@@ -74,7 +76,7 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> {
 
 impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F>
 where
-    F: Fn(&ty::AdtDef) -> NeedsDropResult<I>,
+    F: Fn(&ty::AdtDef, SubstsRef<'tcx>) -> NeedsDropResult<I>,
     I: Iterator<Item = Ty<'tcx>>,
 {
     type Item = NeedsDropResult<Ty<'tcx>>;
@@ -138,7 +140,7 @@ where
                     // `ManuallyDrop`. If it's a struct or enum without a `Drop`
                     // impl then check whether the field types need `Drop`.
                     ty::Adt(adt_def, substs) => {
-                        let tys = match (self.adt_components)(adt_def) {
+                        let tys = match (self.adt_components)(adt_def, substs) {
                             Err(e) => return Some(Err(e)),
                             Ok(tys) => tys,
                         };
@@ -171,22 +173,44 @@ where
     }
 }
 
+enum DtorType {
+    /// Type has a `Drop` but it is considered insignificant.
+    /// Check the query `adt_significant_drop_tys` for understanding
+    /// "significant" / "insignificant".
+    Insignificant,
+
+    /// Type has a `Drop` implentation.
+    Significant,
+}
+
 // This is a helper function for `adt_drop_tys` and `adt_significant_drop_tys`.
 // Depending on the implentation of `adt_has_dtor`, it is used to check if the
 // ADT has a destructor or if the ADT only has a significant destructor. For
 // understanding significant destructor look at `adt_significant_drop_tys`.
-fn adt_drop_tys_helper(
-    tcx: TyCtxt<'_>,
+fn adt_drop_tys_helper<'tcx>(
+    tcx: TyCtxt<'tcx>,
     def_id: DefId,
-    adt_has_dtor: impl Fn(&ty::AdtDef) -> bool,
-) -> Result<&ty::List<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)
 }
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 2a7e1ef351b..3b7c92818f6 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -155,6 +155,7 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "BTreeMap")]
+#[rustc_insignificant_dtor]
 pub struct BTreeMap<K, V> {
     root: Option<Root<K, V>>,
     length: usize,
@@ -331,6 +332,7 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for IterMut<'_, K, V> {
 /// [`into_iter`]: IntoIterator::into_iter
 /// [`IntoIterator`]: core::iter::IntoIterator
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
 pub struct IntoIter<K, V> {
     range: LazyLeafRange<marker::Dying, K, V>,
     length: usize,
diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs
index 0b60c2aa9f6..a769c558b4f 100644
--- a/library/alloc/src/collections/linked_list.rs
+++ b/library/alloc/src/collections/linked_list.rs
@@ -46,6 +46,7 @@ mod tests;
 /// [`VecDeque`]: super::vec_deque::VecDeque
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "LinkedList")]
+#[rustc_insignificant_dtor]
 pub struct LinkedList<T> {
     head: Option<NonNull<Node<T>>>,
     tail: Option<NonNull<Node<T>>>,
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index 10144cc17bf..cae0f29af83 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -90,6 +90,7 @@ const MAXIMUM_ZST_CAPACITY: usize = 1 << (usize::BITS - 1); // Largest possible
 /// [`make_contiguous`]: VecDeque::make_contiguous
 #[cfg_attr(not(test), rustc_diagnostic_item = "vecdeque_type")]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
 pub struct VecDeque<
     T,
     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 3648271c620..81e97805a72 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -305,6 +305,7 @@ struct RcBox<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>>,
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
index 0bd152f17a6..4cb0a4b10bd 100644
--- a/library/alloc/src/vec/into_iter.rs
+++ b/library/alloc/src/vec/into_iter.rs
@@ -22,6 +22,7 @@ use core::slice::{self};
 /// let iter: std::vec::IntoIter<_> = v.into_iter();
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
 pub struct IntoIter<
     T,
     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 4440b1f599f..c37ec375561 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -396,6 +396,7 @@ mod spec_extend;
 /// [owned slice]: Box
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")]
+#[rustc_insignificant_dtor]
 pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
     buf: RawVec<T, A>,
     len: usize,
diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs
index ecdbf098819..822747dd0e8 100644
--- a/library/core/src/array/iter.rs
+++ b/library/core/src/array/iter.rs
@@ -10,6 +10,7 @@ use crate::{
 
 /// A by-value [array] iterator.
 #[stable(feature = "array_value_iter", since = "1.51.0")]
+#[rustc_insignificant_dtor]
 pub struct IntoIter<T, const N: usize> {
     /// This is the array we are iterating over.
     ///
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index 862f411ebe0..f96906be540 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -205,6 +205,7 @@ use crate::sys;
 
 #[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_type")]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
 pub struct HashMap<K, V, S = RandomState> {
     base: base::HashMap<K, V, S>,
 }
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed
index beebb118399..b0fc5120f08 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed
@@ -4,6 +4,14 @@
 
 use std::thread;
 
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+    fn drop(&mut self) {
+        println!("{:?} dropped", self.0);
+    }
+}
+
 /* Test Send Trait Migration */
 struct SendPointer(*mut i32);
 unsafe impl Send for SendPointer {}
@@ -42,19 +50,19 @@ fn test_sync_trait() {
 }
 
 /* Test Clone Trait Migration */
-struct S(String);
+struct S(Foo);
 struct T(i32);
 
 struct U(S, T);
 
 impl Clone for U {
     fn clone(&self) -> Self {
-        U(S(String::from("Hello World")), T(0))
+        U(S(Foo(0)), T(0))
     }
 }
 
 fn test_clone_trait() {
-    let f = U(S(String::from("Hello World")), T(0));
+    let f = U(S(Foo(0)), T(0));
     let c = || {
         let _ = &f;
         //~^ ERROR: `Clone` trait implementation for closure and drop order
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs
index 812ecae262f..2bcf9a795ed 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs
@@ -4,6 +4,14 @@
 
 use std::thread;
 
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+    fn drop(&mut self) {
+        println!("{:?} dropped", self.0);
+    }
+}
+
 /* Test Send Trait Migration */
 struct SendPointer(*mut i32);
 unsafe impl Send for SendPointer {}
@@ -42,19 +50,19 @@ fn test_sync_trait() {
 }
 
 /* Test Clone Trait Migration */
-struct S(String);
+struct S(Foo);
 struct T(i32);
 
 struct U(S, T);
 
 impl Clone for U {
     fn clone(&self) -> Self {
-        U(S(String::from("Hello World")), T(0))
+        U(S(Foo(0)), T(0))
     }
 }
 
 fn test_clone_trait() {
-    let f = U(S(String::from("Hello World")), T(0));
+    let f = U(S(Foo(0)), T(0));
     let c = || {
         //~^ ERROR: `Clone` trait implementation for closure and drop order
         //~| NOTE: in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone`
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr
index 98396abb6ff..8d2d3553d40 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr
@@ -1,5 +1,5 @@
 error: changes to closure capture in Rust 2021 will affect `Send` trait implementation for closure
-  --> $DIR/auto_traits.rs:14:19
+  --> $DIR/auto_traits.rs:22:19
    |
 LL |     thread::spawn(move || unsafe {
    |                   ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send`
@@ -24,7 +24,7 @@ LL |         *fptr.0 = 20;
  ...
 
 error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure
-  --> $DIR/auto_traits.rs:34:19
+  --> $DIR/auto_traits.rs:42:19
    |
 LL |     thread::spawn(move || unsafe {
    |                   ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send`
@@ -44,7 +44,7 @@ LL |         *fptr.0.0 = 20;
  ...
 
 error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order
-  --> $DIR/auto_traits.rs:58:13
+  --> $DIR/auto_traits.rs:66:13
    |
 LL |     let c = || {
    |             ^^ in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone`
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed
index f91454aa211..9a6db588c8b 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed
@@ -3,6 +3,14 @@
 // check-pass
 #![warn(rust_2021_compatibility)]
 
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+    fn drop(&mut self) {
+        println!("{:?} dropped", self.0);
+    }
+}
+
 macro_rules! m {
     (@ $body:expr) => {{
         let f = || $body;
@@ -15,11 +23,11 @@ macro_rules! m {
 }
 
 fn main() {
-    let a = (1.to_string(), 2.to_string());
+    let a = (Foo(0), Foo(1));
     m!({
         let _ = &a;
         //~^ HELP: add a dummy
         let x = a.0;
-        println!("{}", x);
+        println!("{:?}", x);
     });
 }
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs
index 5a1026d0433..08cc24b4b3f 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs
@@ -3,6 +3,14 @@
 // check-pass
 #![warn(rust_2021_compatibility)]
 
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+    fn drop(&mut self) {
+        println!("{:?} dropped", self.0);
+    }
+}
+
 macro_rules! m {
     (@ $body:expr) => {{
         let f = || $body;
@@ -15,10 +23,10 @@ macro_rules! m {
 }
 
 fn main() {
-    let a = (1.to_string(), 2.to_string());
+    let a = (Foo(0), Foo(1));
     m!({
         //~^ HELP: add a dummy
         let x = a.0;
-        println!("{}", x);
+        println!("{:?}", x);
     });
 }
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr
index e6e5598f6d2..a2a9da5f87c 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr
@@ -1,5 +1,5 @@
 warning: changes to closure capture in Rust 2021 will affect drop order
-  --> $DIR/closure-body-macro-fragment.rs:8:17
+  --> $DIR/closure-body-macro-fragment.rs:16:17
    |
 LL |           let f = || $body;
    |  _________________^
@@ -15,7 +15,7 @@ LL | /     m!({
 LL | |
 LL | |         let x = a.0;
    | |                 --- in Rust 2018, this closure captures all of `a`, but in Rust 2021, it will only capture `a.0`
-LL | |         println!("{}", x);
+LL | |         println!("{:?}", x);
 LL | |     });
    | |_______- in this macro invocation
    |
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed
index c82bc369f43..2652bf5988e 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed
@@ -1,169 +1,38 @@
+// run-pass
 // run-rustfix
 
 #![deny(rust_2021_incompatible_closure_captures)]
-//~^ NOTE: the lint level is defined here
+#![allow(unused)]
 
 // Test cases for types that implement an insignificant drop (stlib defined)
 
-// `t` needs Drop because one of its elements needs drop,
-// therefore precise capture might affect drop ordering
-fn test1_all_need_migration() {
-    let t = (String::new(), String::new());
-    let t1 = (String::new(), String::new());
-    let t2 = (String::new(), String::new());
+macro_rules! test_insig_dtor_for_type {
+    ($t: ty, $disambiguator: ident) => {
+        mod $disambiguator {
+            use std::collections::*;
+            use std::rc::Rc;
+            use std::sync::Mutex;
 
-    let c = || {
-        let _ = (&t, &t1, &t2);
-        //~^ ERROR: drop order
-        //~| NOTE: for more information, see
-        //~| HELP: add a dummy let to cause `t`, `t1`, `t2` to be fully captured
+            fn test_for_type(t: $t) {
+                let tup = (Mutex::new(0), t);
 
-        let _t = t.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-        let _t1 = t1.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0`
-        let _t2 = t2.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t2`, but in Rust 2021, it will only capture `t2.0`
+                let _c = || tup.0;
+            }
+        }
     };
-
-    c();
 }
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
-//~| in Rust 2018, `t2` is dropped here, but in Rust 2021, only `t2.0` will be dropped here as part of the closure
-
-// String implements drop and therefore should be migrated.
-// But in this test cases, `t2` is completely captured and when it is dropped won't be affected
-fn test2_only_precise_paths_need_migration() {
-    let t = (String::new(), String::new());
-    let t1 = (String::new(), String::new());
-    let t2 = (String::new(), String::new());
-
-    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() {}
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs
index 57ab15ae8f2..2652bf5988e 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs
@@ -1,162 +1,38 @@
+// run-pass
 // run-rustfix
 
 #![deny(rust_2021_incompatible_closure_captures)]
-//~^ NOTE: the lint level is defined here
+#![allow(unused)]
 
 // Test cases for types that implement an insignificant drop (stlib defined)
 
-// `t` needs Drop because one of its elements needs drop,
-// therefore precise capture might affect drop ordering
-fn test1_all_need_migration() {
-    let t = (String::new(), String::new());
-    let t1 = (String::new(), String::new());
-    let t2 = (String::new(), String::new());
+macro_rules! test_insig_dtor_for_type {
+    ($t: ty, $disambiguator: ident) => {
+        mod $disambiguator {
+            use std::collections::*;
+            use std::rc::Rc;
+            use std::sync::Mutex;
 
-    let c = || {
-        //~^ ERROR: drop order
-        //~| NOTE: for more information, see
-        //~| HELP: add a dummy let to cause `t`, `t1`, `t2` to be fully captured
+            fn test_for_type(t: $t) {
+                let tup = (Mutex::new(0), t);
 
-        let _t = t.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-        let _t1 = t1.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0`
-        let _t2 = t2.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t2`, but in Rust 2021, it will only capture `t2.0`
+                let _c = || tup.0;
+            }
+        }
     };
-
-    c();
 }
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
-//~| in Rust 2018, `t2` is dropped here, but in Rust 2021, only `t2.0` will be dropped here as part of the closure
-
-// String implements drop and therefore should be migrated.
-// But in this test cases, `t2` is completely captured and when it is dropped won't be affected
-fn test2_only_precise_paths_need_migration() {
-    let t = (String::new(), String::new());
-    let t1 = (String::new(), String::new());
-    let t2 = (String::new(), String::new());
-
-    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
index 7989a8fa5cc..00000000000
--- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr
+++ /dev/null
@@ -1,161 +0,0 @@
-error: changes to closure capture in Rust 2021 will affect drop order
-  --> $DIR/insignificant_drop.rs:15:13
-   |
-LL |     let c = || {
-   |             ^^
-...
-LL |         let _t = t.0;
-   |                  --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-LL |
-LL |         let _t1 = t1.0;
-   |                   ---- in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0`
-LL |
-LL |         let _t2 = t2.0;
-   |                   ---- in Rust 2018, this closure captures all of `t2`, but in Rust 2021, it will only capture `t2.0`
-...
-LL | }
-   | -
-   | |
-   | in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-   | in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
-   | in Rust 2018, `t2` is dropped here, but in Rust 2021, only `t2.0` will be dropped here as part of the closure
-   |
-note: the lint level is defined here
-  --> $DIR/insignificant_drop.rs:3:9
-   |
-LL | #![deny(rust_2021_incompatible_closure_captures)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: for more information, see <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
-
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed
index e672d9266fc..d985e3bb9ec 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed
@@ -5,13 +5,15 @@
 #![feature(rustc_attrs)]
 #![allow(unused)]
 
+use std::sync::Mutex;
+
+    #[rustc_insignificant_dtor]
 struct InsignificantDropPoint {
     x: i32,
-    y: i32,
+    y: Mutex<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 {});
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs
index 45850ec5f36..f95d34eeb29 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs
@@ -5,13 +5,15 @@
 #![feature(rustc_attrs)]
 #![allow(unused)]
 
+use std::sync::Mutex;
+
+    #[rustc_insignificant_dtor]
 struct InsignificantDropPoint {
     x: i32,
-    y: i32,
+    y: Mutex<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 {});
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr
index 961834aca19..832a81711b1 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr
@@ -1,5 +1,5 @@
 error: changes to closure capture in Rust 2021 will affect drop order
-  --> $DIR/insignificant_drop_attr_migrations.rs:37:13
+  --> $DIR/insignificant_drop_attr_migrations.rs:39:13
    |
 LL |     let c = || {
    |             ^^
@@ -23,7 +23,7 @@ LL +         let _ = &t;
    |
 
 error: changes to closure capture in Rust 2021 will affect drop order
-  --> $DIR/insignificant_drop_attr_migrations.rs:57:13
+  --> $DIR/insignificant_drop_attr_migrations.rs:59:13
    |
 LL |     let c = move || {
    |             ^^^^^^^
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs
index a527bf42e57..3f184a67fba 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs
@@ -3,6 +3,7 @@
 #![deny(rust_2021_incompatible_closure_captures)]
 #![feature(rustc_attrs)]
 #![allow(unused)]
+#[rustc_insignificant_dtor]
 
 struct InsignificantDropPoint {
     x: i32,
@@ -10,7 +11,6 @@ struct InsignificantDropPoint {
 }
 
 impl Drop for InsignificantDropPoint {
-    #[rustc_insignificant_dtor]
     fn drop(&mut self) {}
 }
 
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/macro.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/macro.fixed
index b9dd8a20b09..31fe494dc79 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/macro.fixed
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/macro.fixed
@@ -5,8 +5,17 @@
 #![deny(rust_2021_incompatible_closure_captures)]
 //~^ NOTE: the lint level is defined here
 
+
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+    fn drop(&mut self) {
+        println!("{:?} dropped", self.0);
+    }
+}
+
 fn main() {
-    let a = ("hey".to_string(), "123".to_string());
+    let a = (Foo(0), Foo(1));
     let _ = || { let _ = &a; dbg!(a.0) };
     //~^ ERROR: drop order
     //~| NOTE: will only capture `a.0`
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/macro.rs b/src/test/ui/closures/2229_closure_analysis/migrations/macro.rs
index f7ccdb754b8..0f0c4974922 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/macro.rs
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/macro.rs
@@ -5,8 +5,17 @@
 #![deny(rust_2021_incompatible_closure_captures)]
 //~^ NOTE: the lint level is defined here
 
+
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+    fn drop(&mut self) {
+        println!("{:?} dropped", self.0);
+    }
+}
+
 fn main() {
-    let a = ("hey".to_string(), "123".to_string());
+    let a = (Foo(0), Foo(1));
     let _ = || dbg!(a.0);
     //~^ ERROR: drop order
     //~| NOTE: will only capture `a.0`
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr
index d1f959dfc52..5046a4bcbb4 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr
@@ -1,5 +1,5 @@
 error: changes to closure capture in Rust 2021 will affect drop order
-  --> $DIR/macro.rs:10:13
+  --> $DIR/macro.rs:19:13
    |
 LL |     let _ = || dbg!(a.0);
    |             ^^^^^^^^---^
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed
index ef90257474a..11218eff133 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed
@@ -4,7 +4,22 @@
 
 use std::thread;
 
-struct S(String);
+#[derive(Debug)]
+struct Foo(String);
+impl Drop for Foo {
+    fn drop(&mut self) {
+        println!("{:?} dropped", self.0);
+    }
+}
+
+impl Foo {
+    fn from(s: &str) -> Self {
+        Self(String::from(s))
+    }
+}
+
+
+struct S(Foo);
 
 #[derive(Clone)]
 struct T(i32);
@@ -13,13 +28,13 @@ struct U(S, T);
 
 impl Clone for U {
     fn clone(&self) -> Self {
-        U(S(String::from("Hello World")), T(0))
+        U(S(Foo::from("Hello World")), T(0))
     }
 }
 
 fn test_multi_issues() {
-    let f1 = U(S(String::from("foo")), T(0));
-    let f2 = U(S(String::from("bar")), T(0));
+    let f1 = U(S(Foo::from("foo")), T(0));
+    let f2 = U(S(Foo::from("bar")), T(0));
     let c = || {
         let _ = (&f1, &f2);
         //~^ ERROR: `Clone` trait implementation for closure and drop order
@@ -39,7 +54,7 @@ fn test_multi_issues() {
 //~^ NOTE: in Rust 2018, `f2` is dropped here, but in Rust 2021, only `f2.1` will be dropped here as part of the closure
 
 fn test_capturing_all_disjoint_fields_individually() {
-    let f1 = U(S(String::from("foo")), T(0));
+    let f1 = U(S(Foo::from("foo")), T(0));
     let c = || {
         let _ = &f1;
         //~^ ERROR: `Clone` trait implementation for closure
@@ -60,12 +75,12 @@ struct U1(S, T, S);
 
 impl Clone for U1 {
     fn clone(&self) -> Self {
-        U1(S(String::from("foo")), T(0), S(String::from("bar")))
+        U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")))
     }
 }
 
 fn test_capturing_several_disjoint_fields_individually_1() {
-    let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar")));
+    let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
     let c = || {
         let _ = &f1;
         //~^ ERROR: `Clone` trait implementation for closure
@@ -85,7 +100,7 @@ fn test_capturing_several_disjoint_fields_individually_1() {
 }
 
 fn test_capturing_several_disjoint_fields_individually_2() {
-    let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar")));
+    let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
     let c = || {
         let _ = &f1;
         //~^ ERROR: `Clone` trait implementation for closure and drop order
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs
index b9644c18d28..02f2faa2e87 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs
@@ -4,7 +4,22 @@
 
 use std::thread;
 
-struct S(String);
+#[derive(Debug)]
+struct Foo(String);
+impl Drop for Foo {
+    fn drop(&mut self) {
+        println!("{:?} dropped", self.0);
+    }
+}
+
+impl Foo {
+    fn from(s: &str) -> Self {
+        Self(String::from(s))
+    }
+}
+
+
+struct S(Foo);
 
 #[derive(Clone)]
 struct T(i32);
@@ -13,13 +28,13 @@ struct U(S, T);
 
 impl Clone for U {
     fn clone(&self) -> Self {
-        U(S(String::from("Hello World")), T(0))
+        U(S(Foo::from("Hello World")), T(0))
     }
 }
 
 fn test_multi_issues() {
-    let f1 = U(S(String::from("foo")), T(0));
-    let f2 = U(S(String::from("bar")), T(0));
+    let f1 = U(S(Foo::from("foo")), T(0));
+    let f2 = U(S(Foo::from("bar")), T(0));
     let c = || {
         //~^ ERROR: `Clone` trait implementation for closure and drop order
         //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
@@ -38,7 +53,7 @@ fn test_multi_issues() {
 //~^ NOTE: in Rust 2018, `f2` is dropped here, but in Rust 2021, only `f2.1` will be dropped here as part of the closure
 
 fn test_capturing_all_disjoint_fields_individually() {
-    let f1 = U(S(String::from("foo")), T(0));
+    let f1 = U(S(Foo::from("foo")), T(0));
     let c = || {
         //~^ ERROR: `Clone` trait implementation for closure
         //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
@@ -58,12 +73,12 @@ struct U1(S, T, S);
 
 impl Clone for U1 {
     fn clone(&self) -> Self {
-        U1(S(String::from("foo")), T(0), S(String::from("bar")))
+        U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")))
     }
 }
 
 fn test_capturing_several_disjoint_fields_individually_1() {
-    let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar")));
+    let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
     let c = || {
         //~^ ERROR: `Clone` trait implementation for closure
         //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
@@ -82,7 +97,7 @@ fn test_capturing_several_disjoint_fields_individually_1() {
 }
 
 fn test_capturing_several_disjoint_fields_individually_2() {
-    let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar")));
+    let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
     let c = || {
         //~^ ERROR: `Clone` trait implementation for closure and drop order
         //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr
index 8bee950c13e..d425db5aa99 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr
@@ -1,5 +1,5 @@
 error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order
-  --> $DIR/multi_diagnostics.rs:23:13
+  --> $DIR/multi_diagnostics.rs:38:13
    |
 LL |     let c = || {
    |             ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
@@ -26,7 +26,7 @@ LL +         let _ = (&f1, &f2);
    |
 
 error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure
-  --> $DIR/multi_diagnostics.rs:42:13
+  --> $DIR/multi_diagnostics.rs:57:13
    |
 LL |     let c = || {
    |             ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
@@ -42,7 +42,7 @@ LL +         let _ = &f1;
    |
 
 error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure
-  --> $DIR/multi_diagnostics.rs:67:13
+  --> $DIR/multi_diagnostics.rs:82:13
    |
 LL |     let c = || {
    |             ^^
@@ -64,7 +64,7 @@ LL +         let _ = &f1;
    |
 
 error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order
-  --> $DIR/multi_diagnostics.rs:86:13
+  --> $DIR/multi_diagnostics.rs:101:13
    |
 LL |     let c = || {
    |             ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
@@ -89,7 +89,7 @@ LL +         let _ = &f1;
    |
 
 error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure
-  --> $DIR/multi_diagnostics.rs:119:19
+  --> $DIR/multi_diagnostics.rs:134:19
    |
 LL |     thread::spawn(move || unsafe {
    |                   ^^^^^^^^^^^^^^
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed
index aca0b2a96ac..63e4000e833 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed
@@ -165,7 +165,7 @@ fn test7_move_closures_non_copy_types_might_need_migration() {
 fn test8_drop_order_and_blocks() {
     {
         let tuple =
-          (String::from("foo"), String::from("bar"));
+          (Foo(0), Foo(1));
         {
             let c = || {
                 let _ = &tuple;
@@ -184,7 +184,7 @@ fn test8_drop_order_and_blocks() {
 
 fn test9_drop_order_and_nested_closures() {
     let tuple =
-        (String::from("foo"), String::from("bar"));
+        (Foo(0), Foo(1));
     let b = || {
         let c = || {
             let _ = &tuple;
@@ -202,6 +202,19 @@ fn test9_drop_order_and_nested_closures() {
     b();
 }
 
+// Test that we migrate if drop order of Vec<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();
 }
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs
index fd4134a7704..9d9c54298cf 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs
@@ -158,7 +158,7 @@ fn test7_move_closures_non_copy_types_might_need_migration() {
 fn test8_drop_order_and_blocks() {
     {
         let tuple =
-          (String::from("foo"), String::from("bar"));
+          (Foo(0), Foo(1));
         {
             let c = || {
                 //~^ ERROR: drop order
@@ -176,7 +176,7 @@ fn test8_drop_order_and_blocks() {
 
 fn test9_drop_order_and_nested_closures() {
     let tuple =
-        (String::from("foo"), String::from("bar"));
+        (Foo(0), Foo(1));
     let b = || {
         let c = || {
             //~^ ERROR: drop order
@@ -193,6 +193,19 @@ fn test9_drop_order_and_nested_closures() {
     b();
 }
 
+// Test that we migrate if drop order of Vec<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();
 }
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr
index e9170eba3f1..fa1f83c3782 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr
@@ -195,5 +195,22 @@ LL ~         let c = || {
 LL +             let _ = &tuple;
    |
 
-error: aborting due to 9 previous errors
+error: changes to closure capture in Rust 2021 will affect drop order
+  --> $DIR/significant_drop.rs:201:18
+   |
+LL |         let _c = || tup.0;
+   |                  ^^^-----
+   |                     |
+   |                     in Rust 2018, this closure captures all of `tup`, but in Rust 2021, it will only capture `tup.0`
+...
+LL | }
+   | - in Rust 2018, `tup` is dropped here, but in Rust 2021, only `tup.0` will be dropped here as part of the closure
+   |
+   = note: for more information, see <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