diff options
| -rw-r--r-- | clippy_lints/src/lib.rs | 4 | ||||
| -rw-r--r-- | clippy_lints/src/non_send_field_in_send_ty.rs | 53 | ||||
| -rw-r--r-- | clippy_lints/src/utils/conf.rs | 2 | ||||
| -rw-r--r-- | tests/ui/non_send_field_in_send_ty.stderr | 28 |
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, |
