about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/lib.rs4
-rw-r--r--clippy_lints/src/non_send_field_in_send_ty.rs53
-rw-r--r--clippy_lints/src/utils/conf.rs2
-rw-r--r--tests/ui/non_send_field_in_send_ty.stderr28
4 files changed, 45 insertions, 42 deletions
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index f9d660972cb..50b55e5f79a 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -535,8 +535,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || Box::new(feature_name::FeatureName));
     store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator));
     store.register_late_pass(move || Box::new(if_then_panic::IfThenPanic));
-    let enable_raw_pointer_heuristic = conf.enable_raw_pointer_heuristic;
-    store.register_late_pass(move || Box::new(non_send_field_in_send_ty::NonSendFieldInSendTy::new(enable_raw_pointer_heuristic)));
+    let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send;
+    store.register_late_pass(move || Box::new(non_send_field_in_send_ty::NonSendFieldInSendTy::new(enable_raw_pointer_heuristic_for_send)));
 }
 
 #[rustfmt::skip]
diff --git a/clippy_lints/src/non_send_field_in_send_ty.rs b/clippy_lints/src/non_send_field_in_send_ty.rs
index 706214cb3d5..83f6f786d26 100644
--- a/clippy_lints/src/non_send_field_in_send_ty.rs
+++ b/clippy_lints/src/non_send_field_in_send_ty.rs
@@ -42,7 +42,7 @@ declare_clippy_lint! {
     /// unsafe impl<T> Send for ExampleStruct<T> {}
     /// ```
     /// Use thread-safe types like [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html)
-    /// and specify correct bounds on generic type parameters (`T: Send`).
+    /// or specify correct bounds on generic type parameters (`T: Send`).
     pub NON_SEND_FIELD_IN_SEND_TY,
     nursery,
     "there is field that does not implement `Send` in a `Send` struct"
@@ -125,7 +125,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy {
                             for field in non_send_fields {
                                 diag.span_note(
                                     field.span,
-                                    &format!("the field `{}` has type `{}` which is not `Send`", field.name, field.ty),
+                                    &format!("the field `{}` has type `{}` which is `!Send`", field.name, field.ty),
                                 );
 
                                 match field.generic_params.len() {
@@ -165,7 +165,7 @@ impl<'tcx> NonSendField<'tcx> {
 }
 
 /// Given a type, collect all of its generic parameters.
-/// Example: MyStruct<P, Box<Q, R>> => vec![P, Q, R]
+/// Example: `MyStruct<P, Box<Q, R>>` => `vec![P, Q, R]`
 fn collect_generic_params<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Vec<Ty<'tcx>> {
     ty.walk(cx.tcx)
         .filter_map(|inner| match inner.unpack() {
@@ -184,31 +184,34 @@ fn ty_implements_send_or_copy(cx: &LateContext<'tcx>, ty: Ty<'tcx>, send_trait:
 /// Heuristic to allow cases like `Vec<*const u8>`
 fn ty_allowed_with_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, send_trait: DefId) -> bool {
     if ty_implements_send_or_copy(cx, ty, send_trait) {
-        true
-    } else {
-        // The type is known to be `!Send` and `!Copy`
-        match ty.kind() {
-            ty::Tuple(_) => ty
-                .tuple_fields()
-                .all(|ty| ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait)),
-            ty::Array(ty, _) | ty::Slice(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait),
-            ty::Adt(_, substs) => {
-                if contains_raw_pointer(cx, ty) {
-                    // descends only if ADT contains any raw pointers
-                    substs.iter().all(|generic_arg| match generic_arg.unpack() {
-                        GenericArgKind::Type(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait),
-                        GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => true,
-                    })
-                } else {
-                    false
-                }
-            },
-            ty::RawPtr(_) => true,
-            _ => false,
-        }
+        return true;
+    }
+
+    // The type is known to be `!Send` and `!Copy`
+    match ty.kind() {
+        ty::Tuple(_) => ty
+            .tuple_fields()
+            .all(|ty| ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait)),
+        ty::Array(ty, _) | ty::Slice(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait),
+        ty::Adt(_, substs) => {
+            if contains_raw_pointer(cx, ty) {
+                // descends only if ADT contains any raw pointers
+                substs.iter().all(|generic_arg| match generic_arg.unpack() {
+                    GenericArgKind::Type(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait),
+                    // Lifetimes and const generics are not solid part of ADT and ignored
+                    GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => true,
+                })
+            } else {
+                false
+            }
+        },
+        // Raw pointers are `!Send` but allowed by the heuristic
+        ty::RawPtr(_) => true,
+        _ => false,
     }
 }
 
+/// Checks if the type contains any raw pointers in substs (including nested ones).
 fn contains_raw_pointer<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> bool {
     for ty_node in target_ty.walk(cx.tcx) {
         if_chain! {
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 177c0fd375c..e6233f73a57 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -287,7 +287,7 @@ define_Conf! {
     /// Lint: NON_SEND_FIELD_IN_SEND_TY.
     ///
     /// Whether to apply the raw pointer heuristic in `non_send_field_in_send_ty` lint.
-    (enable_raw_pointer_heuristic: bool = true),
+    (enable_raw_pointer_heuristic_for_send: bool = true),
 }
 
 /// Search for the configuration file.
diff --git a/tests/ui/non_send_field_in_send_ty.stderr b/tests/ui/non_send_field_in_send_ty.stderr
index 327ef9fc2d6..6c7312d0152 100644
--- a/tests/ui/non_send_field_in_send_ty.stderr
+++ b/tests/ui/non_send_field_in_send_ty.stderr
@@ -5,7 +5,7 @@ LL | unsafe impl<T> Send for RingBuffer<T> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::non-send-field-in-send-ty` implied by `-D warnings`
-note: the field `data` has type `std::vec::Vec<std::cell::UnsafeCell<T>>` which is not `Send`
+note: the field `data` has type `std::vec::Vec<std::cell::UnsafeCell<T>>` which is `!Send`
   --> $DIR/non_send_field_in_send_ty.rs:11:5
    |
 LL |     data: Vec<UnsafeCell<T>>,
@@ -18,7 +18,7 @@ error: this implementation is unsound, as some fields in `MvccRwLock<T>` are `!S
 LL | unsafe impl<T> Send for MvccRwLock<T> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the field `lock` has type `std::sync::Mutex<std::boxed::Box<T>>` which is not `Send`
+note: the field `lock` has type `std::sync::Mutex<std::boxed::Box<T>>` which is `!Send`
   --> $DIR/non_send_field_in_send_ty.rs:21:5
    |
 LL |     lock: Mutex<Box<T>>,
@@ -31,7 +31,7 @@ error: this implementation is unsound, as some fields in `ArcGuard<RC, T>` are `
 LL | unsafe impl<RC, T: Send> Send for ArcGuard<RC, T> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the field `head` has type `std::sync::Arc<RC>` which is not `Send`
+note: the field `head` has type `std::sync::Arc<RC>` which is `!Send`
   --> $DIR/non_send_field_in_send_ty.rs:29:5
    |
 LL |     head: Arc<RC>,
@@ -44,7 +44,7 @@ error: this implementation is unsound, as some fields in `DeviceHandle<T>` are `
 LL | unsafe impl<T: UsbContext> Send for DeviceHandle<T> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the field `context` has type `T` which is not `Send`
+note: the field `context` has type `T` which is `!Send`
   --> $DIR/non_send_field_in_send_ty.rs:44:5
    |
 LL |     context: T,
@@ -57,7 +57,7 @@ error: this implementation is unsound, as some fields in `NoGeneric` are `!Send`
 LL | unsafe impl Send for NoGeneric {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the field `rc_is_not_send` has type `std::rc::Rc<std::string::String>` which is not `Send`
+note: the field `rc_is_not_send` has type `std::rc::Rc<std::string::String>` which is `!Send`
   --> $DIR/non_send_field_in_send_ty.rs:52:5
    |
 LL |     rc_is_not_send: Rc<String>,
@@ -70,19 +70,19 @@ error: this implementation is unsound, as some fields in `MultiField<T>` are `!S
 LL | unsafe impl<T> Send for MultiField<T> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the field `field1` has type `T` which is not `Send`
+note: the field `field1` has type `T` which is `!Send`
   --> $DIR/non_send_field_in_send_ty.rs:58:5
    |
 LL |     field1: T,
    |     ^^^^^^^^^
    = help: add `T: Send` bound in `Send` impl
-note: the field `field2` has type `T` which is not `Send`
+note: the field `field2` has type `T` which is `!Send`
   --> $DIR/non_send_field_in_send_ty.rs:59:5
    |
 LL |     field2: T,
    |     ^^^^^^^^^
    = help: add `T: Send` bound in `Send` impl
-note: the field `field3` has type `T` which is not `Send`
+note: the field `field3` has type `T` which is `!Send`
   --> $DIR/non_send_field_in_send_ty.rs:60:5
    |
 LL |     field3: T,
@@ -95,7 +95,7 @@ error: this implementation is unsound, as some fields in `MyOption<T>` are `!Sen
 LL | unsafe impl<T> Send for MyOption<T> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the field `0` has type `T` which is not `Send`
+note: the field `0` has type `T` which is `!Send`
   --> $DIR/non_send_field_in_send_ty.rs:66:12
    |
 LL |     MySome(T),
@@ -108,7 +108,7 @@ error: this implementation is unsound, as some fields in `MultiParam<A, B>` are
 LL | unsafe impl<A, B> Send for MultiParam<A, B> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the field `vec` has type `std::vec::Vec<(A, B)>` which is not `Send`
+note: the field `vec` has type `std::vec::Vec<(A, B)>` which is `!Send`
   --> $DIR/non_send_field_in_send_ty.rs:74:5
    |
 LL |     vec: Vec<(A, B)>,
@@ -121,7 +121,7 @@ error: this implementation is unsound, as some fields in `HeuristicTest` are `!S
 LL | unsafe impl Send for HeuristicTest {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the field `field4` has type `(*const NonSend, std::rc::Rc<u8>)` which is not `Send`
+note: the field `field4` has type `(*const NonSend, std::rc::Rc<u8>)` which is `!Send`
   --> $DIR/non_send_field_in_send_ty.rs:90:5
    |
 LL |     field4: (*const NonSend, Rc<u8>),
@@ -134,7 +134,7 @@ error: this implementation is unsound, as some fields in `AttrTest3<T>` are `!Se
 LL | unsafe impl<T> Send for AttrTest3<T> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the field `0` has type `T` which is not `Send`
+note: the field `0` has type `T` which is `!Send`
   --> $DIR/non_send_field_in_send_ty.rs:109:11
    |
 LL |     Enum2(T),
@@ -147,7 +147,7 @@ error: this implementation is unsound, as some fields in `Complex<P, u32>` are `
 LL | unsafe impl<P> Send for Complex<P, u32> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the field `field1` has type `P` which is not `Send`
+note: the field `field1` has type `P` which is `!Send`
   --> $DIR/non_send_field_in_send_ty.rs:118:5
    |
 LL |     field1: A,
@@ -160,7 +160,7 @@ error: this implementation is unsound, as some fields in `Complex<Q, std::sync::
 LL | unsafe impl<Q: Send> Send for Complex<Q, MutexGuard<'static, bool>> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the field `field2` has type `std::sync::MutexGuard<'static, bool>` which is not `Send`
+note: the field `field2` has type `std::sync::MutexGuard<'static, bool>` which is `!Send`
   --> $DIR/non_send_field_in_send_ty.rs:119:5
    |
 LL |     field2: B,