]> git.lizzy.rs Git - rust.git/commitdiff
Add additional migrations to handle auto-traits and clone traits
authorRoxane <roxane.fruytier@hotmail.com>
Thu, 8 Apr 2021 23:09:08 +0000 (19:09 -0400)
committerRoxane <roxane.fruytier@hotmail.com>
Thu, 6 May 2021 18:17:59 +0000 (14:17 -0400)
Combine all 2229 migrations under one flag name

27 files changed:
compiler/rustc_hir/src/lang_items.rs
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_typeck/src/check/upvar.rs
library/core/src/marker.rs
library/std/src/panic.rs
src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr [new file with mode: 0644]
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
src/test/ui/closures/2229_closure_analysis/migrations/issue-78720.rs
src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.fixed
src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.rs
src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr
src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/migrations/no_migrations.rs
src/test/ui/closures/2229_closure_analysis/migrations/precise.fixed
src/test/ui/closures/2229_closure_analysis/migrations/precise.rs
src/test/ui/closures/2229_closure_analysis/migrations/precise.stderr
src/test/ui/closures/2229_closure_analysis/migrations/precise_no_migrations.rs
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 498000db50f436a854a9c6e86de2180272aebea5..7b788b13b9f7d41aa197123f2f3398558e8adda0 100644 (file)
@@ -343,4 +343,7 @@ pub fn extract<'a, F>(check_name: F, attrs: &'a [ast::Attribute]) -> Option<(Sym
     Range,                   sym::Range,               range_struct,               Target::Struct;
     RangeToInclusive,        sym::RangeToInclusive,    range_to_inclusive_struct,  Target::Struct;
     RangeTo,                 sym::RangeTo,             range_to_struct,            Target::Struct;
+    Send,                    sym::send,                send_trait,                 Target::Trait;
+    UnwindSafe,              sym::unwind_safe,         unwind_safe_trait,          Target::Trait;
+    RefUnwindSafe,           sym::ref_unwind_safe,     ref_unwind_safe_trait,      Target::Trait;
 }
index beb4d36597cfc800ba1be769d31a2d34b1ae2d49..15246971bae02e82175430a15b2b5f92a65ba82f 100644 (file)
         UNSUPPORTED_NAKED_FUNCTIONS,
         MISSING_ABI,
         SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
-        DISJOINT_CAPTURE_DROP_REORDER,
+        DISJOINT_CAPTURE_MIGRATION,
         LEGACY_DERIVE_HELPERS,
         PROC_MACRO_BACK_COMPAT,
         OR_PATTERNS_BACK_COMPAT,
 }
 
 declare_lint! {
-    /// The `disjoint_capture_drop_reorder` lint detects variables that aren't completely
+    /// The `disjoint_capture_migration` lint detects variables that aren't completely
     /// captured when the feature `capture_disjoint_fields` is enabled and it affects the Drop
     /// order of at least one path starting at this variable.
+    /// It can also detect when a variable implements a trait, but one of its field does not and
+    /// the field is captured by a closure and used with the assumption that said field implements
+    /// the same trait as the root variable.
     ///
-    /// ### Example
+    /// ### Example of drop reorder
     ///
     /// ```rust,compile_fail
-    /// # #![deny(disjoint_capture_drop_reorder)]
+    /// # #![deny(disjoint_capture_migration)]
     /// # #![allow(unused)]
     /// struct FancyInteger(i32);
     ///
     ///
     /// In the above example `p.y` will be dropped at the end of `f` instead of with `c` if
     /// the feature `capture_disjoint_fields` is enabled.
-    pub DISJOINT_CAPTURE_DROP_REORDER,
+    ///
+    /// ### Example of auto-trait
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(disjoint_capture_migration)]
+    /// use std::thread;
+    ///
+    /// struct Pointer (*mut i32);
+    /// unsafe impl Send for Pointer {}
+    ///
+    /// fn main() {
+    ///     let mut f = 10;
+    ///     let fptr = Pointer(&mut f as *mut i32);
+    ///     thread::spawn(move || unsafe {
+    ///         *fptr.0 = 20;
+    ///     });
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In the above example `fptr.0` is captured when feature `capture_disjoint_fields` is enabled.
+    /// The field is of type *mut i32 which doesn't implement Send, making the code invalid as the
+    /// field cannot be sent between thread safely.
+    pub DISJOINT_CAPTURE_MIGRATION,
     Allow,
-    "Drop reorder because of `capture_disjoint_fields`"
-
+    "Drop reorder and auto traits error because of `capture_disjoint_fields`"
 }
 
 declare_lint_pass!(UnusedDocComment => [UNUSED_DOC_COMMENTS]);
index b2dac10c83face662b8d66db8d8b1dd7570b6bba..6ba68fb767d61ae0a194d0f7455fa6899f4a89a0 100644 (file)
         receiver,
         recursion_limit,
         reexport_test_harness_main,
+        ref_unwind_safe,
         reference,
         reflect,
         reg,
         self_in_typedefs,
         self_struct_ctor,
         semitransparent,
+        send,
         send_trait,
         shl,
         shl_assign,
         unused_qualifications,
         unwind,
         unwind_attributes,
+        unwind_safe,
         unwrap,
         unwrap_or,
         use_extern_macros,
index 751eebb9f95644ed2eaa0b0271f2122f6a475ab8..81c0010fd24d98b23142963f6b9bd7366e7a67f9 100644 (file)
 use rustc_infer::infer::UpvarRegion;
 use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind};
 use rustc_middle::mir::FakeReadCause;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeckResults, UpvarSubsts};
+use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, TypeckResults, UpvarSubsts};
 use rustc_session::lint;
 use rustc_span::sym;
 use rustc_span::{MultiSpan, Span, Symbol};
+use rustc_trait_selection::traits::{Obligation, ObligationCause};
 
+use rustc_data_structures::stable_set::FxHashSet;
 use rustc_index::vec::Idx;
 use rustc_target::abi::VariantIdx;
 
@@ -168,7 +170,8 @@ fn analyze_closure(
         self.compute_min_captures(closure_def_id, delegate.capture_information);
 
         let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
-        if should_do_migration_analysis(self.tcx, closure_hir_id) {
+
+        if should_do_disjoint_capture_migration_analysis(self.tcx, closure_hir_id) {
             self.perform_2229_migration_anaysis(closure_def_id, body_id, capture_clause, span);
         }
 
@@ -471,7 +474,7 @@ fn perform_2229_migration_anaysis(
         capture_clause: hir::CaptureBy,
         span: Span,
     ) {
-        let need_migrations = self.compute_2229_migrations(
+        let (need_migrations, reasons) = self.compute_2229_migrations(
             closure_def_id,
             span,
             capture_clause,
@@ -485,12 +488,16 @@ fn perform_2229_migration_anaysis(
             let local_def_id = closure_def_id.expect_local();
             let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
             self.tcx.struct_span_lint_hir(
-                lint::builtin::DISJOINT_CAPTURE_DROP_REORDER,
+                lint::builtin::DISJOINT_CAPTURE_MIGRATION,
                 closure_hir_id,
                 span,
                 |lint| {
                     let mut diagnostics_builder = lint.build(
-                        "drop order affected for closure because of `capture_disjoint_fields`",
+                        format!(
+                            "{} affected for closure because of `capture_disjoint_fields`",
+                            reasons
+                        )
+                        .as_str(),
                     );
                     let closure_body_span = self.tcx.hir().span(body_id.hir_id);
                     let (sugg, app) =
@@ -527,6 +534,188 @@ fn perform_2229_migration_anaysis(
         }
     }
 
+    /// Combines all the reasons for 2229 migrations
+    fn compute_2229_migrations_reasons(
+        &self,
+        auto_trait_reasons: FxHashSet<&str>,
+        drop_reason: bool,
+    ) -> String {
+        let mut reasons = String::new();
+
+        if auto_trait_reasons.len() > 0 {
+            reasons = format!(
+                "{} trait implementation",
+                auto_trait_reasons.clone().into_iter().collect::<Vec<&str>>().join(", ")
+            );
+        }
+
+        if auto_trait_reasons.len() > 0 && drop_reason {
+            reasons = format!("{}, and ", reasons);
+        }
+
+        if drop_reason {
+            reasons = format!("{}drop order", reasons);
+        }
+
+        reasons
+    }
+
+    fn ty_contains_trait(
+        &self,
+        ty: Ty<'tcx>,
+        cause: &ObligationCause<'tcx>,
+        trait_def_id: DefId,
+    ) -> bool {
+        use crate::rustc_middle::ty::ToPredicate;
+        use crate::rustc_middle::ty::WithConstness;
+        use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+        let tcx = self.infcx.tcx;
+
+        let trait_ref = TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, &[]) };
+
+        let obligation = Obligation::new(
+            cause.clone(),
+            self.param_env,
+            trait_ref.without_const().to_predicate(tcx),
+        );
+
+        self.infcx.predicate_may_hold(&obligation)
+    }
+
+    /// Figures out the list of root variables (and their types) that aren't completely
+    /// captured by the closure when `capture_disjoint_fields` is enabled and auto-traits
+    /// differ between the root variable and the captured paths.
+    ///
+    /// The output list would include a root variable if:
+    /// - It would have been captured into the closure when `capture_disjoint_fields` wasn't
+    ///   enabled, **and**
+    /// - It wasn't completely captured by the closure, **and**
+    /// - One of the paths captured does not implement all the auto-traits its root variable
+    ///   implements.
+    fn compute_2229_migrations_for_trait(
+        &self,
+        min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>,
+        _closure_clause: hir::CaptureBy,
+        var_hir_id: hir::HirId,
+    ) -> Option<FxHashSet<&str>> {
+        let root_var_min_capture_list = if let Some(root_var_min_capture_list) =
+            min_captures.and_then(|m| m.get(&var_hir_id))
+        {
+            root_var_min_capture_list
+        } else {
+            return None;
+        };
+
+        let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id));
+
+        let tcx = self.infcx.tcx;
+
+        let cause = ObligationCause::misc(self.tcx.hir().span(var_hir_id), self.body_id);
+
+        let clone_obligation_should_hold = tcx
+            .lang_items()
+            .clone_trait()
+            .map(|clone_trait| self.ty_contains_trait(ty, &cause, clone_trait))
+            .unwrap_or(false);
+        let sync_obligation_should_hold = tcx
+            .lang_items()
+            .sync_trait()
+            .map(|sync_trait| self.ty_contains_trait(ty, &cause, sync_trait))
+            .unwrap_or(false);
+        let send_obligation_should_hold = tcx
+            .lang_items()
+            .send_trait()
+            .map(|send_trait| self.ty_contains_trait(ty, &cause, send_trait))
+            .unwrap_or(false);
+        let unpin_obligation_should_hold = tcx
+            .lang_items()
+            .unpin_trait()
+            .map(|unpin_trait| self.ty_contains_trait(ty, &cause, unpin_trait))
+            .unwrap_or(false);
+        let unwind_safe_obligation_should_hold = tcx
+            .lang_items()
+            .unwind_safe_trait()
+            .map(|unwind_safe_trait| self.ty_contains_trait(ty, &cause, unwind_safe_trait))
+            .unwrap_or(false);
+        let ref_unwind_safe_obligation_should_hold = tcx
+            .lang_items()
+            .ref_unwind_safe_trait()
+            .map(|ref_unwind_safe_trait| self.ty_contains_trait(ty, &cause, ref_unwind_safe_trait))
+            .unwrap_or(false);
+
+        // Check whether catpured fields also implement the trait
+        let mut auto_trait_reasons = FxHashSet::default();
+
+        for capture in root_var_min_capture_list.iter() {
+            let ty = capture.place.ty();
+
+            let clone_obligation_holds_for_capture = tcx
+                .lang_items()
+                .clone_trait()
+                .map(|clone_trait| self.ty_contains_trait(ty, &cause, clone_trait))
+                .unwrap_or(false);
+            let sync_obligation_holds_for_capture = tcx
+                .lang_items()
+                .sync_trait()
+                .map(|sync_trait| self.ty_contains_trait(ty, &cause, sync_trait))
+                .unwrap_or(false);
+            let send_obligation_holds_for_capture = tcx
+                .lang_items()
+                .send_trait()
+                .map(|send_trait| self.ty_contains_trait(ty, &cause, send_trait))
+                .unwrap_or(false);
+            let unpin_obligation_holds_for_capture = tcx
+                .lang_items()
+                .unpin_trait()
+                .map(|unpin_trait| self.ty_contains_trait(ty, &cause, unpin_trait))
+                .unwrap_or(false);
+            let unwind_safe_obligation_holds_for_capture = tcx
+                .lang_items()
+                .unwind_safe_trait()
+                .map(|unwind_safe| self.ty_contains_trait(ty, &cause, unwind_safe))
+                .unwrap_or(false);
+            let ref_unwind_safe_obligation_holds_for_capture = tcx
+                .lang_items()
+                .ref_unwind_safe_trait()
+                .map(|ref_unwind_safe_trait| {
+                    self.ty_contains_trait(ty, &cause, ref_unwind_safe_trait)
+                })
+                .unwrap_or(false);
+
+            if !clone_obligation_holds_for_capture && clone_obligation_should_hold {
+                auto_trait_reasons.insert("`Clone`");
+            }
+
+            if !sync_obligation_holds_for_capture && sync_obligation_should_hold {
+                auto_trait_reasons.insert("`Sync`");
+            }
+
+            if !send_obligation_holds_for_capture && send_obligation_should_hold {
+                auto_trait_reasons.insert("`Send`");
+            }
+
+            if !unpin_obligation_holds_for_capture && unpin_obligation_should_hold {
+                auto_trait_reasons.insert("`Unpin`");
+            }
+
+            if !unwind_safe_obligation_holds_for_capture && unwind_safe_obligation_should_hold {
+                auto_trait_reasons.insert("`UnwindSafe`");
+            }
+
+            if !ref_unwind_safe_obligation_holds_for_capture
+                && ref_unwind_safe_obligation_should_hold
+            {
+                auto_trait_reasons.insert("`RefUnwindSafe`");
+            }
+        }
+
+        if auto_trait_reasons.len() > 0 {
+            return Some(auto_trait_reasons);
+        }
+
+        return None;
+    }
+
     /// Figures out the list of root variables (and their types) that aren't completely
     /// captured by the closure when `capture_disjoint_fields` is enabled and drop order of
     /// some path starting at that root variable **might** be affected.
@@ -536,76 +725,126 @@ fn perform_2229_migration_anaysis(
     ///   enabled, **and**
     /// - It wasn't completely captured by the closure, **and**
     /// - One of the paths starting at this root variable, that is not captured needs Drop.
-    fn compute_2229_migrations(
+    fn compute_2229_migrations_for_drop(
         &self,
         closure_def_id: DefId,
         closure_span: Span,
-        closure_clause: hir::CaptureBy,
         min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>,
-    ) -> Vec<hir::HirId> {
-        let upvars = if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
-            upvars
-        } else {
-            return vec![];
-        };
+        closure_clause: hir::CaptureBy,
+        var_hir_id: hir::HirId,
+    ) -> Option<()> {
+        let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id));
 
-        let mut need_migrations = Vec::new();
+        if !ty.needs_drop(self.tcx, self.tcx.param_env(closure_def_id.expect_local())) {
+            return None;
+        }
 
-        for (&var_hir_id, _) in upvars.iter() {
-            let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id));
+        let root_var_min_capture_list = if let Some(root_var_min_capture_list) =
+            min_captures.and_then(|m| m.get(&var_hir_id))
+        {
+            root_var_min_capture_list
+        } else {
+            // The upvar is mentioned within the closure but no path starting from it is
+            // used.
 
-            if !ty.needs_drop(self.tcx, self.tcx.param_env(closure_def_id.expect_local())) {
-                continue;
+            match closure_clause {
+                // Only migrate if closure is a move closure
+                hir::CaptureBy::Value => return Some(()),
+                hir::CaptureBy::Ref => {}
             }
 
-            let root_var_min_capture_list = if let Some(root_var_min_capture_list) =
-                min_captures.and_then(|m| m.get(&var_hir_id))
-            {
-                root_var_min_capture_list
-            } else {
-                // The upvar is mentioned within the closure but no path starting from it is
-                // used.
+            return None;
+        };
 
-                match closure_clause {
-                    // Only migrate if closure is a move closure
-                    hir::CaptureBy::Value => need_migrations.push(var_hir_id),
+        let projections_list = root_var_min_capture_list
+            .iter()
+            .filter_map(|captured_place| match captured_place.info.capture_kind {
+                // Only care about captures that are moved into the closure
+                ty::UpvarCapture::ByValue(..) => Some(captured_place.place.projections.as_slice()),
+                ty::UpvarCapture::ByRef(..) => None,
+            })
+            .collect::<Vec<_>>();
 
-                    hir::CaptureBy::Ref => {}
-                }
+        let is_moved = !projections_list.is_empty();
 
-                continue;
-            };
+        let is_not_completely_captured =
+            root_var_min_capture_list.iter().any(|capture| capture.place.projections.len() > 0);
 
-            let projections_list = root_var_min_capture_list
-                .iter()
-                .filter_map(|captured_place| match captured_place.info.capture_kind {
-                    // Only care about captures that are moved into the closure
-                    ty::UpvarCapture::ByValue(..) => {
-                        Some(captured_place.place.projections.as_slice())
-                    }
-                    ty::UpvarCapture::ByRef(..) => None,
-                })
-                .collect::<Vec<_>>();
+        if is_moved
+            && is_not_completely_captured
+            && self.has_significant_drop_outside_of_captures(
+                closure_def_id,
+                closure_span,
+                ty,
+                projections_list,
+            )
+        {
+            return Some(());
+        }
 
-            let is_moved = !projections_list.is_empty();
+        return None;
+    }
 
-            let is_not_completely_captured =
-                root_var_min_capture_list.iter().any(|capture| capture.place.projections.len() > 0);
+    /// Figures out the list of root variables (and their types) that aren't completely
+    /// captured by the closure when `capture_disjoint_fields` is enabled and either drop
+    /// order of some path starting at that root variable **might** be affected or auto-traits
+    /// differ between the root variable and the captured paths.
+    ///
+    /// The output list would include a root variable if:
+    /// - It would have been moved into the closure when `capture_disjoint_fields` wasn't
+    ///   enabled, **and**
+    /// - It wasn't completely captured by the closure, **and**
+    /// - One of the paths starting at this root variable, that is not captured needs Drop **or**
+    /// - One of the paths captured does not implement all the auto-traits its root variable
+    ///   implements.
+    fn compute_2229_migrations(
+        &self,
+        closure_def_id: DefId,
+        closure_span: Span,
+        closure_clause: hir::CaptureBy,
+        min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>,
+    ) -> (Vec<hir::HirId>, String) {
+        let upvars = if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
+            upvars
+        } else {
+            return (Vec::new(), format!(""));
+        };
 
-            if is_moved
-                && is_not_completely_captured
-                && self.has_significant_drop_outside_of_captures(
-                    closure_def_id,
-                    closure_span,
-                    ty,
-                    projections_list,
-                )
+        let mut need_migrations = Vec::new();
+        let mut auto_trait_reasons = FxHashSet::default();
+        let mut drop_reorder_reason = false;
+
+        // Perform auto-trait analysis
+        for (&var_hir_id, _) in upvars.iter() {
+            // println!("CHeck auto traits");
+            let mut need_some_migrations = false;
+            if let Some(trait_migration_cause) =
+                self.compute_2229_migrations_for_trait(min_captures, closure_clause, var_hir_id)
             {
+                need_some_migrations = true;
+                auto_trait_reasons.extend(trait_migration_cause);
+            }
+
+            if let Some(_) = self.compute_2229_migrations_for_drop(
+                closure_def_id,
+                closure_span,
+                min_captures,
+                closure_clause,
+                var_hir_id,
+            ) {
+                need_some_migrations = true;
+                drop_reorder_reason = true;
+            }
+
+            if need_some_migrations {
                 need_migrations.push(var_hir_id);
             }
         }
 
-        need_migrations
+        (
+            need_migrations,
+            self.compute_2229_migrations_reasons(auto_trait_reasons, drop_reorder_reason),
+        )
     }
 
     /// This is a helper function to `compute_2229_migrations_precise_pass`. Provided the type
@@ -1544,9 +1783,8 @@ fn var_name(tcx: TyCtxt<'_>, var_hir_id: hir::HirId) -> Symbol {
     tcx.hir().name(var_hir_id)
 }
 
-fn should_do_migration_analysis(tcx: TyCtxt<'_>, closure_id: hir::HirId) -> bool {
-    let (level, _) =
-        tcx.lint_level_at_node(lint::builtin::DISJOINT_CAPTURE_DROP_REORDER, closure_id);
+fn should_do_disjoint_capture_migration_analysis(tcx: TyCtxt<'_>, closure_id: hir::HirId) -> bool {
+    let (level, _) = tcx.lint_level_at_node(lint::builtin::DISJOINT_CAPTURE_MIGRATION, closure_id);
 
     !matches!(level, lint::Level::Allow)
 }
index fb957348bebd3837dbfc60d43efa5c389fb7fb2b..2b2404550433ddb6bb9eca9a1ff20d61885e5e35 100644 (file)
@@ -31,6 +31,7 @@
 /// [ub]: ../../reference/behavior-considered-undefined.html
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "send_trait")]
+#[cfg_attr(not(bootstrap), lang = "send")]
 #[rustc_on_unimplemented(
     message = "`{Self}` cannot be sent between threads safely",
     label = "`{Self}` cannot be sent between threads safely"
index 3e634239ad3015f689226f40ebaa7e422dd3f735..0442f70aa65233c846b41d426b80cca36504e154 100644 (file)
@@ -132,6 +132,7 @@ pub fn panic_any<M: 'static + Any + Send>(msg: M) -> ! {
 /// [`AssertUnwindSafe`] wrapper struct can be used to force this trait to be
 /// implemented for any closed over variables passed to `catch_unwind`.
 #[stable(feature = "catch_unwind", since = "1.9.0")]
+#[cfg_attr(not(bootstrap), lang = "unwind_safe")]
 #[rustc_on_unimplemented(
     message = "the type `{Self}` may not be safely transferred across an unwind boundary",
     label = "`{Self}` may not be safely transferred across an unwind boundary"
@@ -147,6 +148,7 @@ pub fn panic_any<M: 'static + Any + Send>(msg: M) -> ! {
 /// This is a "helper marker trait" used to provide impl blocks for the
 /// [`UnwindSafe`] trait, for more information see that documentation.
 #[stable(feature = "catch_unwind", since = "1.9.0")]
+#[cfg_attr(not(bootstrap), lang = "ref_unwind_safe")]
 #[rustc_on_unimplemented(
     message = "the type `{Self}` may contain interior mutability and a reference may not be safely \
                transferrable across a catch_unwind boundary",
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
new file mode 100644 (file)
index 0000000..fcefbdc
--- /dev/null
@@ -0,0 +1,67 @@
+// run-rustfix
+#![deny(disjoint_capture_migration)]
+
+use std::thread;
+
+/* Test Send Trait */
+struct SendPointer (*mut i32);
+unsafe impl Send for SendPointer {}
+
+fn test_send_trait() {
+    let mut f = 10;
+    let fptr = SendPointer(&mut f as *mut i32);
+    thread::spawn(move || { let _ = &fptr; unsafe {
+        //~^ ERROR: `Send` trait implementation affected for closure because of `capture_disjoint_fields`
+        //~| HELP: add a dummy let to cause `fptr` to be fully captured
+        *fptr.0 = 20;
+    } });
+}
+
+/* Test Sync Trait */
+struct CustomInt (*mut i32);
+struct SyncPointer (CustomInt);
+unsafe impl Sync for SyncPointer {}
+unsafe impl Send for CustomInt {}
+
+fn test_sync_trait() {
+    let mut f = 10;
+    let f = CustomInt(&mut f as *mut i32);
+    let fptr = SyncPointer(f);
+    thread::spawn(move || { let _ = &fptr; unsafe {
+        //~^ ERROR: `Sync`, `Send` trait implementation affected for closure because of `capture_disjoint_fields`
+        //~| HELP: add a dummy let to cause `fptr` to be fully captured
+        *fptr.0.0 = 20;
+    } });
+}
+
+/* Test Clone Trait */
+struct S(String);
+struct T(i32);
+
+struct U(S,T);
+
+impl Clone for U {
+    fn clone(&self) -> Self {
+        U(S(String::from("Hello World")), T(0))
+    }
+}
+
+fn test_clone_trait() {
+    let f = U(S(String::from("Hello World")), T(0));
+    let c = || { let _ = &f; 
+        //~^ ERROR: `Clone` trait implementation, and drop order affected for closure because of `capture_disjoint_fields`
+        //~| HELP: add a dummy let to cause `f` to be fully captured
+        let f_1 = f.1;
+        println!("{:?}", f_1.0);
+    };
+
+    let c_clone = c.clone();
+
+    c_clone();
+}
+
+fn main() {
+    test_send_trait();
+    test_sync_trait();
+    test_clone_trait();
+}
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
new file mode 100644 (file)
index 0000000..3babff1
--- /dev/null
@@ -0,0 +1,67 @@
+// run-rustfix
+#![deny(disjoint_capture_migration)]
+
+use std::thread;
+
+/* Test Send Trait */
+struct SendPointer (*mut i32);
+unsafe impl Send for SendPointer {}
+
+fn test_send_trait() {
+    let mut f = 10;
+    let fptr = SendPointer(&mut f as *mut i32);
+    thread::spawn(move || unsafe {
+        //~^ ERROR: `Send` trait implementation affected for closure because of `capture_disjoint_fields`
+        //~| HELP: add a dummy let to cause `fptr` to be fully captured
+        *fptr.0 = 20;
+    });
+}
+
+/* Test Sync Trait */
+struct CustomInt (*mut i32);
+struct SyncPointer (CustomInt);
+unsafe impl Sync for SyncPointer {}
+unsafe impl Send for CustomInt {}
+
+fn test_sync_trait() {
+    let mut f = 10;
+    let f = CustomInt(&mut f as *mut i32);
+    let fptr = SyncPointer(f);
+    thread::spawn(move || unsafe {
+        //~^ ERROR: `Sync`, `Send` trait implementation affected for closure because of `capture_disjoint_fields`
+        //~| HELP: add a dummy let to cause `fptr` to be fully captured
+        *fptr.0.0 = 20;
+    });
+}
+
+/* Test Clone Trait */
+struct S(String);
+struct T(i32);
+
+struct U(S,T);
+
+impl Clone for U {
+    fn clone(&self) -> Self {
+        U(S(String::from("Hello World")), T(0))
+    }
+}
+
+fn test_clone_trait() {
+    let f = U(S(String::from("Hello World")), T(0));
+    let c = || {
+        //~^ ERROR: `Clone` trait implementation, and drop order affected for closure because of `capture_disjoint_fields`
+        //~| HELP: add a dummy let to cause `f` to be fully captured
+        let f_1 = f.1;
+        println!("{:?}", f_1.0);
+    };
+
+    let c_clone = c.clone();
+
+    c_clone();
+}
+
+fn main() {
+    test_send_trait();
+    test_sync_trait();
+    test_clone_trait();
+}
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
new file mode 100644 (file)
index 0000000..6e3723b
--- /dev/null
@@ -0,0 +1,69 @@
+error: `Send` trait implementation affected for closure because of `capture_disjoint_fields`
+  --> $DIR/auto_traits.rs:13:19
+   |
+LL |       thread::spawn(move || unsafe {
+   |  ___________________^
+LL | |
+LL | |
+LL | |         *fptr.0 = 20;
+LL | |     });
+   | |_____^
+   |
+note: the lint level is defined here
+  --> $DIR/auto_traits.rs:2:9
+   |
+LL | #![deny(disjoint_capture_migration)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: add a dummy let to cause `fptr` to be fully captured
+   |
+LL |     thread::spawn(move || { let _ = &fptr; unsafe {
+LL |
+LL |
+LL |         *fptr.0 = 20;
+LL |     } });
+   |
+
+error: `Sync`, `Send` trait implementation affected for closure because of `capture_disjoint_fields`
+  --> $DIR/auto_traits.rs:30:19
+   |
+LL |       thread::spawn(move || unsafe {
+   |  ___________________^
+LL | |
+LL | |
+LL | |         *fptr.0.0 = 20;
+LL | |     });
+   | |_____^
+   |
+help: add a dummy let to cause `fptr` to be fully captured
+   |
+LL |     thread::spawn(move || { let _ = &fptr; unsafe {
+LL |
+LL |
+LL |         *fptr.0.0 = 20;
+LL |     } });
+   |
+
+error: `Clone` trait implementation, and drop order affected for closure because of `capture_disjoint_fields`
+  --> $DIR/auto_traits.rs:51:13
+   |
+LL |       let c = || {
+   |  _____________^
+LL | |
+LL | |
+LL | |         let f_1 = f.1;
+LL | |         println!("{:?}", f_1.0);
+LL | |     };
+   | |_____^
+   |
+help: add a dummy let to cause `f` to be fully captured
+   |
+LL |     let c = || { let _ = &f; 
+LL |
+LL |
+LL |         let f_1 = f.1;
+LL |         println!("{:?}", f_1.0);
+LL |     };
+   |
+
+error: aborting due to 3 previous errors
+
index 300f67e8b1e811db3e101a203eabf51a517132e3..3770e93239a8efde54d3a754109eee92b0667d20 100644 (file)
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![deny(disjoint_capture_drop_reorder)]
+#![deny(disjoint_capture_migration)]
 //~^ NOTE: the lint level is defined here
 
 // Test cases for types that implement a insignificant drop (stlib defined)
index a17c70d3e287780e0355a17c072cc11ff708f5c3..2015ab7e9b8cb5b5bb52a2243960b2d84034dfcc 100644 (file)
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![deny(disjoint_capture_drop_reorder)]
+#![deny(disjoint_capture_migration)]
 //~^ NOTE: the lint level is defined here
 
 // Test cases for types that implement a insignificant drop (stlib defined)
index 69c12d2bb56c0f914eba16073767067714c9e0d0..69a99f7a53a53a30ff483a6b1d06a405cb1b20fd 100644 (file)
@@ -14,8 +14,8 @@ LL | |     };
 note: the lint level is defined here
   --> $DIR/insignificant_drop.rs:3:9
    |
-LL | #![deny(disjoint_capture_drop_reorder)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![deny(disjoint_capture_migration)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: add a dummy let to cause `t`, `t1`, `t2` to be fully captured
    |
 LL |     let c = || { let _ = (&t, &t1, &t2); 
index 3a6af00254c5a847b9c7c69d444c7823736bfa26..ee3138ea69ee8ac6bb65080b7ad5a4c2e13589fc 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 
-#![warn(disjoint_capture_drop_reorder)]
+#![warn(disjoint_capture_migration)]
 
 fn main() {
     if let a = "" {
index a3e51a2b8e91af1c264f196dc7f19ddceb7e1c40..979c023fc53ace02c460c10ed526bda026266289 100644 (file)
@@ -1,5 +1,5 @@
 // run-rustfix
-#![deny(disjoint_capture_drop_reorder)]
+#![deny(disjoint_capture_migration)]
 //~^ NOTE: the lint level is defined here
 
 // Test the two possible cases for automated migartion using rustfix
index 0eb837b6888350413e5d74a7d3bf7680a1ccb016..c2a700bd9caa00be1e8b379d7bd29792eec315c3 100644 (file)
@@ -1,5 +1,5 @@
 // run-rustfix
-#![deny(disjoint_capture_drop_reorder)]
+#![deny(disjoint_capture_migration)]
 //~^ NOTE: the lint level is defined here
 
 // Test the two possible cases for automated migartion using rustfix
index e6173217edc2fb9b95cb4b46ddb626e4136a3773..a968d3a093b154b40b219bdb15eee8a723424128 100644 (file)
@@ -12,8 +12,8 @@ LL | |     };
 note: the lint level is defined here
   --> $DIR/migrations_rustfix.rs:2:9
    |
-LL | #![deny(disjoint_capture_drop_reorder)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![deny(disjoint_capture_migration)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: add a dummy let to cause `t` to be fully captured
    |
 LL |     let c = || { let _ = &t; 
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed
new file mode 100644 (file)
index 0000000..95463a6
--- /dev/null
@@ -0,0 +1,39 @@
+// run-rustfix
+
+#![deny(disjoint_capture_migration)]
+// ignore-wasm32-bare compiled with panic=abort by default
+
+#![feature(fn_traits)]
+#![feature(never_type)]
+
+use std::panic;
+
+fn foo_diverges() -> ! { panic!() }
+
+fn assert_panics<F>(f: F) where F: FnOnce() {
+    let f = panic::AssertUnwindSafe(f);
+    let result = panic::catch_unwind(move || { let _ = &f; 
+        //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` trait implementation affected for closure because of `capture_disjoint_fields`
+        //~| HELP: add a dummy let to cause `f` to be fully captured
+        f.0()
+    });
+    if let Ok(..) = result {
+        panic!("diverging function returned");
+    }
+}
+
+fn test_fn_ptr_panic<T>(mut t: T)
+    where T: Fn() -> !
+{
+    let as_fn = <T as Fn<()>>::call;
+    assert_panics(|| as_fn(&t, ()));
+    let as_fn_mut = <T as FnMut<()>>::call_mut;
+    assert_panics(|| as_fn_mut(&mut t, ()));
+    let as_fn_once = <T as FnOnce<()>>::call_once;
+    assert_panics(|| as_fn_once(t, ()));
+}
+
+fn main() {
+    test_fn_ptr_panic(foo_diverges);
+    test_fn_ptr_panic(foo_diverges as fn() -> !);
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs
new file mode 100644 (file)
index 0000000..fae7fc8
--- /dev/null
@@ -0,0 +1,39 @@
+// run-rustfix
+
+#![deny(disjoint_capture_migration)]
+// ignore-wasm32-bare compiled with panic=abort by default
+
+#![feature(fn_traits)]
+#![feature(never_type)]
+
+use std::panic;
+
+fn foo_diverges() -> ! { panic!() }
+
+fn assert_panics<F>(f: F) where F: FnOnce() {
+    let f = panic::AssertUnwindSafe(f);
+    let result = panic::catch_unwind(move || {
+        //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` trait implementation affected for closure because of `capture_disjoint_fields`
+        //~| HELP: add a dummy let to cause `f` to be fully captured
+        f.0()
+    });
+    if let Ok(..) = result {
+        panic!("diverging function returned");
+    }
+}
+
+fn test_fn_ptr_panic<T>(mut t: T)
+    where T: Fn() -> !
+{
+    let as_fn = <T as Fn<()>>::call;
+    assert_panics(|| as_fn(&t, ()));
+    let as_fn_mut = <T as FnMut<()>>::call_mut;
+    assert_panics(|| as_fn_mut(&mut t, ()));
+    let as_fn_once = <T as FnOnce<()>>::call_once;
+    assert_panics(|| as_fn_once(t, ()));
+}
+
+fn main() {
+    test_fn_ptr_panic(foo_diverges);
+    test_fn_ptr_panic(foo_diverges as fn() -> !);
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr
new file mode 100644 (file)
index 0000000..bbc8eb9
--- /dev/null
@@ -0,0 +1,27 @@
+error: `UnwindSafe`, `RefUnwindSafe` trait implementation affected for closure because of `capture_disjoint_fields`
+  --> $DIR/mir_calls_to_shims.rs:15:38
+   |
+LL |       let result = panic::catch_unwind(move || {
+   |  ______________________________________^
+LL | |
+LL | |
+LL | |         f.0()
+LL | |     });
+   | |_____^
+   |
+note: the lint level is defined here
+  --> $DIR/mir_calls_to_shims.rs:3:9
+   |
+LL | #![deny(disjoint_capture_migration)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: add a dummy let to cause `f` to be fully captured
+   |
+LL |     let result = panic::catch_unwind(move || { let _ = &f; 
+LL |
+LL |
+LL |         f.0()
+LL |     });
+   |
+
+error: aborting due to previous error
+
index 73592ce04c28f9cfebdbb727369675d319db2939..420d66fba5e306015460b1fa296755f1c98b71a8 100644 (file)
@@ -2,7 +2,7 @@
 
 // Set of test cases that don't need migrations
 
-#![deny(disjoint_capture_drop_reorder)]
+#![deny(disjoint_capture_migration)]
 
 
 // Copy types as copied by the closure instead of being moved into the closure
index b739035c784223ffd5d5ba38f89b5b677deea308..5c93fce92507b8c07dcada0e834ef434559c38f8 100644 (file)
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![deny(disjoint_capture_drop_reorder)]
+#![deny(disjoint_capture_migration)]
 
 #[derive(Debug)]
 struct Foo(i32);
index e1f29c9d0e9d8cb9544bb6712fbf3e7d112709b7..fb4af00aa06166b2b9f9cd777ad70fbaec4493e4 100644 (file)
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![deny(disjoint_capture_drop_reorder)]
+#![deny(disjoint_capture_migration)]
 
 #[derive(Debug)]
 struct Foo(i32);
index 7135ded13c2563a6d104c7f6d30f643d7b3c5986..0cd191e2c98c5a3c9c40db94615b81de1d461b9f 100644 (file)
@@ -13,8 +13,8 @@ LL | |     };
 note: the lint level is defined here
   --> $DIR/precise.rs:3:9
    |
-LL | #![deny(disjoint_capture_drop_reorder)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![deny(disjoint_capture_migration)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: add a dummy let to cause `t` to be fully captured
    |
 LL |     let c = || { let _ = &t; 
index 8af48501ca2952670fe96143363d1c8ad0f3b0a5..e3a7220bf09d239fe0e0555bee613fd7946a70f8 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 
-#![deny(disjoint_capture_drop_reorder)]
+#![deny(disjoint_capture_migration)]
 
 #[derive(Debug)]
 struct Foo(i32);
index e1b212153f431053fb8ce06ddd176a021a589bb1..1fa0fb3db2f8d9d779dcc182baf812f765d2e0a1 100644 (file)
@@ -1,5 +1,5 @@
 // run-rustfix
-#![deny(disjoint_capture_drop_reorder)]
+#![deny(disjoint_capture_migration)]
 //~^ NOTE: the lint level is defined here
 
 // Test cases for types that implement a significant drop (user defined)
index 106b2933515156249b2946595722b10504d115d8..1f0efbe1ebc43313664dcefa08c6bd755db1e3a4 100644 (file)
@@ -1,5 +1,5 @@
 // run-rustfix
-#![deny(disjoint_capture_drop_reorder)]
+#![deny(disjoint_capture_migration)]
 //~^ NOTE: the lint level is defined here
 
 // Test cases for types that implement a significant drop (user defined)
index ee29fe1306059377efa3d28209282d9fd2bb92c5..91e75ffb81a96217e392fad1e8592846962c2935 100644 (file)
@@ -14,8 +14,8 @@ LL | |     };
 note: the lint level is defined here
   --> $DIR/significant_drop.rs:2:9
    |
-LL | #![deny(disjoint_capture_drop_reorder)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![deny(disjoint_capture_migration)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: add a dummy let to cause `t`, `t1`, `t2` to be fully captured
    |
 LL |     let c = || { let _ = (&t, &t1, &t2);