From 5c33ba66c2d0d578bae2b2ca706fdac1a2834575 Mon Sep 17 00:00:00 2001 From: Tunglies <77394545+Tunglies@users.noreply.github.com> Date: Wed, 3 Dec 2025 04:36:32 +0800 Subject: [PATCH 1/2] feat(rwlock_atomic): add new lints for using RwLock with atomic types changelog: [`rwlock_atomic`]: new lint changelog: [`rwlock_integer`]: new lint --- CHANGELOG.md | 2 + README.md | 2 +- book/src/README.md | 2 +- clippy_lints/src/declared_lints.rs | 2 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/rwlock_atomic.rs | 176 +++++++++++++++++++++++++++++ tests/ui/rwlock_atomic.fixed | 49 ++++++++ tests/ui/rwlock_atomic.rs | 49 ++++++++ tests/ui/rwlock_atomic.stderr | 91 +++++++++++++++ 9 files changed, 373 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/rwlock_atomic.rs create mode 100644 tests/ui/rwlock_atomic.fixed create mode 100644 tests/ui/rwlock_atomic.rs create mode 100644 tests/ui/rwlock_atomic.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c81fa47eca9..e7484089a728 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6837,6 +6837,8 @@ Released 2018-09-13 [`return_self_not_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#return_self_not_must_use [`reverse_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#reverse_range_loop [`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges +[`rwlock_atomic`]: https://rust-lang.github.io/rust-clippy/master/index.html#rwlock_atomic +[`rwlock_integer`]: https://rust-lang.github.io/rust-clippy/master/index.html#rwlock_integer [`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition [`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push [`same_name_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_name_method diff --git a/README.md b/README.md index 20a5e997e629..78498c73ae78 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 750 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 800 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category. diff --git a/book/src/README.md b/book/src/README.md index 5d2c3972b060..c5b264c9f703 100644 --- a/book/src/README.md +++ b/book/src/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 750 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 800 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 17bcc3824a7b..7342066dbecc 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -666,6 +666,8 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::returns::LET_AND_RETURN_INFO, crate::returns::NEEDLESS_RETURN_INFO, crate::returns::NEEDLESS_RETURN_WITH_QUESTION_MARK_INFO, + crate::rwlock_atomic::RWLOCK_ATOMIC_INFO, + crate::rwlock_atomic::RWLOCK_INTEGER_INFO, crate::same_name_method::SAME_NAME_METHOD_INFO, crate::self_named_constructors::SELF_NAMED_CONSTRUCTORS_INFO, crate::semicolon_block::SEMICOLON_INSIDE_BLOCK_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index cad36b7f197a..d6c95ed4e670 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -317,6 +317,7 @@ mod replace_box; mod reserve_after_initialization; mod return_self_not_must_use; mod returns; +mod rwlock_atomic; mod same_name_method; mod self_named_constructors; mod semicolon_block; @@ -850,6 +851,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co Box::new(|_| Box::new(volatile_composites::VolatileComposites)), Box::new(|_| Box::::default()), Box::new(move |_| Box::new(manual_ilog2::ManualIlog2::new(conf))), + Box::new(|_| Box::new(rwlock_atomic::RwLock)), // add late passes here, used by `cargo dev new_lint` ]; store.late_passes.extend(late_lints); diff --git a/clippy_lints/src/rwlock_atomic.rs b/clippy_lints/src/rwlock_atomic.rs new file mode 100644 index 000000000000..4e7994abe344 --- /dev/null +++ b/clippy_lints/src/rwlock_atomic.rs @@ -0,0 +1,176 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::res::MaybeDef; +use clippy_utils::source::{IntoSpan, SpanRangeExt}; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::ty_from_hir_ty; +use rustc_errors::{Applicability, Diag}; +use rustc_hir::{self as hir, Expr, ExprKind, Item, ItemKind, LetStmt, QPath}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::mir::Mutability; +use rustc_middle::ty::{self, IntTy, Ty, UintTy}; +use rustc_session::declare_lint_pass; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `RwLock` where an atomic will do. + /// + /// ### Why is this bad? + /// Using a RwLock just to make access to a plain bool or + /// reference sequential is shooting flies with cannons. + /// `std::sync::atomic::AtomicBool` and `std::sync::atomic::AtomicPtr` are leaner and + /// faster. + /// + /// On the other hand, `RwLock`s are, in general, easier to + /// verify correctness. An atomic does not behave the same as + /// an equivalent RwLock. + /// + /// ### Example + /// ```no_run + /// # let y = true; + /// # use std::sync::RwLock; + /// let x = RwLock::new(&y); + /// ``` + /// + /// Use instead: + /// ```no_run + /// # let y = true; + /// # use std::sync::atomic::AtomicBool; + /// let x = AtomicBool::new(y); + /// ``` + #[clippy::version = "1.93.0"] + pub RWLOCK_ATOMIC, + restriction, + "using a RwLock where an atomic value could be used instead." +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `RwLock` where `X` is an integral + /// type. + /// + /// ### Why is this bad? + /// Using a RwLock just to make access to a plain integer + /// sequential is + /// shooting flies with cannons. `std::sync::atomic::AtomicUsize` is leaner and faster. + /// + /// On the other hand, `RwLock`s are, in general, easier to + /// verify correctness. An atomic does not behave the same as + /// an equivalent RwLock. + /// + /// ### Example + /// ```no_run + /// # use std::sync::RwLock; + /// let x = RwLock::new(0usize); + /// ``` + /// + /// Use instead: + /// ```no_run + /// # use std::sync::atomic::AtomicUsize; + /// let x = AtomicUsize::new(0usize); + /// ``` + #[clippy::version = "1.93.0"] + pub RWLOCK_INTEGER, + restriction, + "using a RwLock for an integer type" +} + +declare_lint_pass!(RwLock => [RWLOCK_ATOMIC, RWLOCK_INTEGER]); + +impl<'tcx> LateLintPass<'tcx> for RwLock { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + if !item.span.from_expansion() + && let ItemKind::Static(_, _, ty, body_id) = item.kind + { + let body = cx.tcx.hir_body(body_id); + let mid_ty = ty_from_hir_ty(cx, ty); + check_expr(cx, body.value.peel_blocks(), &TypeAscriptionKind::Required(ty), mid_ty); + } + } + fn check_local(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx LetStmt<'_>) { + if !stmt.span.from_expansion() + && let Some(init) = stmt.init + { + let mid_ty = cx.typeck_results().expr_ty(init); + check_expr(cx, init.peel_blocks(), &TypeAscriptionKind::Optional(stmt.ty), mid_ty); + } + } +} + +enum TypeAscriptionKind<'tcx> { + Required(&'tcx hir::Ty<'tcx>), + Optional(Option<&'tcx hir::Ty<'tcx>>), +} + +fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, ty_ascription: &TypeAscriptionKind<'tcx>, ty: Ty<'tcx>) { + if let ty::Adt(_, subst) = ty.kind() + && ty.is_diag_item(cx, sym::RwLock) + && let rwlock_param = subst.type_at(0) + && let Some(atomic_name) = get_atomic_name(rwlock_param) + { + let msg = "using a `RwLock` where an atomic would do"; + let diag = |diag: &mut Diag<'_, _>| { + if let ExprKind::Call(qpath, [arg]) = expr.kind + && let ExprKind::Path(QPath::TypeRelative(_rwlock, new)) = qpath.kind + && new.ident.name == sym::new + { + let mut applicability = Applicability::MaybeIncorrect; + let arg = Sugg::hir_with_applicability(cx, arg, "_", &mut applicability); + let mut suggs = vec![(expr.span, format!("std::sync::atomic::{atomic_name}::new({arg})"))]; + match ty_ascription { + TypeAscriptionKind::Required(ty_ascription) => { + suggs.push((ty_ascription.span, format!("std::sync::atomic::{atomic_name}"))); + }, + TypeAscriptionKind::Optional(Some(ty_ascription)) => { + let colon_ascription = (cx.sess().source_map()) + .span_extend_to_prev_char_before(ty_ascription.span, ':', true) + .with_leading_whitespace(cx) + .into_span(); + suggs.push((colon_ascription, String::new())); + }, + TypeAscriptionKind::Optional(None) => {}, + } + diag.multipart_suggestion("try", suggs, applicability); + } else { + diag.help(format!("consider using an `{atomic_name}` instead")); + } + diag.help("if you just want the locking behavior and not the internal type, consider using `RwLock<()>`"); + }; + match *rwlock_param.kind() { + ty::Uint(t) if t != UintTy::Usize => span_lint_and_then(cx, RWLOCK_INTEGER, expr.span, msg, diag), + ty::Int(t) if t != IntTy::Isize => span_lint_and_then(cx, RWLOCK_INTEGER, expr.span, msg, diag), + _ => span_lint_and_then(cx, RWLOCK_ATOMIC, expr.span, msg, diag), + } + } +} + +fn get_atomic_name(ty: Ty<'_>) -> Option<&'static str> { + match ty.kind() { + ty::Bool => Some("AtomicBool"), + ty::Uint(uint_ty) => { + match uint_ty { + UintTy::U8 => Some("AtomicU8"), + UintTy::U16 => Some("AtomicU16"), + UintTy::U32 => Some("AtomicU32"), + UintTy::U64 => Some("AtomicU64"), + UintTy::Usize => Some("AtomicUsize"), + // `AtomicU128` is unstable and only available on a few platforms: https://github.com/rust-lang/rust/issues/99069 + UintTy::U128 => None, + } + }, + ty::Int(int_ty) => { + match int_ty { + IntTy::I8 => Some("AtomicI8"), + IntTy::I16 => Some("AtomicI16"), + IntTy::I32 => Some("AtomicI32"), + IntTy::I64 => Some("AtomicI64"), + IntTy::Isize => Some("AtomicIsize"), + // `AtomicU128` is unstable and only available on a few platforms: https://github.com/rust-lang/rust/issues/99069 + IntTy::I128 => None, + } + }, + // `AtomicPtr` only accepts `*mut T` + ty::RawPtr(_, Mutability::Mut) => Some("AtomicPtr"), + _ => None, + } +} diff --git a/tests/ui/rwlock_atomic.fixed b/tests/ui/rwlock_atomic.fixed new file mode 100644 index 000000000000..24cdc3127e24 --- /dev/null +++ b/tests/ui/rwlock_atomic.fixed @@ -0,0 +1,49 @@ +#![warn(clippy::rwlock_integer)] +#![warn(clippy::rwlock_atomic)] +#![allow(clippy::borrow_as_ptr)] + +use std::sync::RwLock; + +fn main() { + let _ = std::sync::atomic::AtomicBool::new(true); + //~^ rwlock_atomic + + let _ = std::sync::atomic::AtomicUsize::new(5usize); + //~^ rwlock_atomic + + let _ = std::sync::atomic::AtomicIsize::new(9isize); + //~^ rwlock_atomic + + let mut x = 4u32; + // `AtomicPtr` only accepts `*mut T`, so this should not lint + let _ = RwLock::new(&x as *const u32); + + let _ = std::sync::atomic::AtomicPtr::new(&mut x as *mut u32); + //~^ rwlock_atomic + + let _ = std::sync::atomic::AtomicU32::new(0u32); + //~^ rwlock_integer + + let _ = std::sync::atomic::AtomicI32::new(0i32); + //~^ rwlock_integer + + let _ = RwLock::new(0f32); // there are no float atomics, so this should not lint + let _ = std::sync::atomic::AtomicU8::new(0u8); + //~^ rwlock_integer + + let _ = std::sync::atomic::AtomicI16::new(0i16); + //~^ rwlock_integer + + let _x = std::sync::atomic::AtomicI8::new(0); + //~^ rwlock_integer + + const X: i64 = 0; + let _ = std::sync::atomic::AtomicI64::new(X); + //~^ rwlock_integer + + // there are no 128 atomics, so these two should not lint + { + let _ = RwLock::new(0u128); + let _x: RwLock = RwLock::new(0); + } +} diff --git a/tests/ui/rwlock_atomic.rs b/tests/ui/rwlock_atomic.rs new file mode 100644 index 000000000000..51bc775a9e38 --- /dev/null +++ b/tests/ui/rwlock_atomic.rs @@ -0,0 +1,49 @@ +#![warn(clippy::rwlock_integer)] +#![warn(clippy::rwlock_atomic)] +#![allow(clippy::borrow_as_ptr)] + +use std::sync::RwLock; + +fn main() { + let _ = RwLock::new(true); + //~^ rwlock_atomic + + let _ = RwLock::new(5usize); + //~^ rwlock_atomic + + let _ = RwLock::new(9isize); + //~^ rwlock_atomic + + let mut x = 4u32; + // `AtomicPtr` only accepts `*mut T`, so this should not lint + let _ = RwLock::new(&x as *const u32); + + let _ = RwLock::new(&mut x as *mut u32); + //~^ rwlock_atomic + + let _ = RwLock::new(0u32); + //~^ rwlock_integer + + let _ = RwLock::new(0i32); + //~^ rwlock_integer + + let _ = RwLock::new(0f32); // there are no float atomics, so this should not lint + let _ = RwLock::new(0u8); + //~^ rwlock_integer + + let _ = RwLock::new(0i16); + //~^ rwlock_integer + + let _x: RwLock = RwLock::new(0); + //~^ rwlock_integer + + const X: i64 = 0; + let _ = RwLock::new(X); + //~^ rwlock_integer + + // there are no 128 atomics, so these two should not lint + { + let _ = RwLock::new(0u128); + let _x: RwLock = RwLock::new(0); + } +} diff --git a/tests/ui/rwlock_atomic.stderr b/tests/ui/rwlock_atomic.stderr new file mode 100644 index 000000000000..da2cd2bbb619 --- /dev/null +++ b/tests/ui/rwlock_atomic.stderr @@ -0,0 +1,91 @@ +error: using a `RwLock` where an atomic would do + --> tests/ui/rwlock_atomic.rs:8:13 + | +LL | let _ = RwLock::new(true); + | ^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicBool::new(true)` + | + = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` + = note: `-D clippy::rwlock-atomic` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::rwlock_atomic)]` + +error: using a `RwLock` where an atomic would do + --> tests/ui/rwlock_atomic.rs:11:13 + | +LL | let _ = RwLock::new(5usize); + | ^^^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicUsize::new(5usize)` + | + = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` + +error: using a `RwLock` where an atomic would do + --> tests/ui/rwlock_atomic.rs:14:13 + | +LL | let _ = RwLock::new(9isize); + | ^^^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicIsize::new(9isize)` + | + = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` + +error: using a `RwLock` where an atomic would do + --> tests/ui/rwlock_atomic.rs:21:13 + | +LL | let _ = RwLock::new(&mut x as *mut u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicPtr::new(&mut x as *mut u32)` + | + = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` + +error: using a `RwLock` where an atomic would do + --> tests/ui/rwlock_atomic.rs:24:13 + | +LL | let _ = RwLock::new(0u32); + | ^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicU32::new(0u32)` + | + = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` + = note: `-D clippy::rwlock-integer` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::rwlock_integer)]` + +error: using a `RwLock` where an atomic would do + --> tests/ui/rwlock_atomic.rs:27:13 + | +LL | let _ = RwLock::new(0i32); + | ^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI32::new(0i32)` + | + = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` + +error: using a `RwLock` where an atomic would do + --> tests/ui/rwlock_atomic.rs:31:13 + | +LL | let _ = RwLock::new(0u8); + | ^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicU8::new(0u8)` + | + = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` + +error: using a `RwLock` where an atomic would do + --> tests/ui/rwlock_atomic.rs:34:13 + | +LL | let _ = RwLock::new(0i16); + | ^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI16::new(0i16)` + | + = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` + +error: using a `RwLock` where an atomic would do + --> tests/ui/rwlock_atomic.rs:37:26 + | +LL | let _x: RwLock = RwLock::new(0); + | ^^^^^^^^^^^^^^ + | + = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` +help: try + | +LL - let _x: RwLock = RwLock::new(0); +LL + let _x = std::sync::atomic::AtomicI8::new(0); + | + +error: using a `RwLock` where an atomic would do + --> tests/ui/rwlock_atomic.rs:41:13 + | +LL | let _ = RwLock::new(X); + | ^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI64::new(X)` + | + = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` + +error: aborting due to 10 previous errors + From 41e7ea07a8976f50d77a882288c36ea37f9341a5 Mon Sep 17 00:00:00 2001 From: Tunglies <77394545+Tunglies@users.noreply.github.com> Date: Tue, 9 Dec 2025 09:04:25 +0800 Subject: [PATCH 2/2] Implement lints for using `RwLock` and `Mutex` where atomic types could be used instead - Added new lints: `RWLOCK_ATOMIC`, `RWLOCK_INTEGER`, `MUTEX_ATOMIC`, and `MUTEX_INTEGER` to check for inappropriate usage of `RwLock` and `Mutex` with atomic types. - Created a new lint pass `SyncGuard` to handle the linting logic for these cases. - Updated tests to cover various scenarios where `RwLock` and `Mutex` are used with atomic types, ensuring that the lints trigger correctly. - Removed outdated test files and added new tests to validate the behavior of the new lints. - Rename rwlock_atomic.rs to rwlock_mutex_atomic.rs --- clippy_lints/src/declared_lints.rs | 8 +- clippy_lints/src/lib.rs | 6 +- clippy_lints/src/rwlock_atomic.rs | 176 ------------------ ...mutex_atomic.rs => rwlock_mutex_atomic.rs} | 101 +++++++++- tests/ui/rwlock_atomic.fixed | 49 ----- tests/ui/rwlock_atomic.rs | 49 ----- tests/ui/rwlock_atomic.stderr | 91 --------- ...atomic.fixed => rwlock_mutex_atomic.fixed} | 32 +++- ...mutex_atomic.rs => rwlock_mutex_atomic.rs} | 32 +++- ...omic.stderr => rwlock_mutex_atomic.stderr} | 119 ++++++++++-- ...le.rs => rwlock_mutex_atomic_unfixable.rs} | 0 ...r => rwlock_mutex_atomic_unfixable.stderr} | 2 +- 12 files changed, 261 insertions(+), 404 deletions(-) delete mode 100644 clippy_lints/src/rwlock_atomic.rs rename clippy_lints/src/{mutex_atomic.rs => rwlock_mutex_atomic.rs} (72%) delete mode 100644 tests/ui/rwlock_atomic.fixed delete mode 100644 tests/ui/rwlock_atomic.rs delete mode 100644 tests/ui/rwlock_atomic.stderr rename tests/ui/{mutex_atomic.fixed => rwlock_mutex_atomic.fixed} (59%) rename tests/ui/{mutex_atomic.rs => rwlock_mutex_atomic.rs} (60%) rename tests/ui/{mutex_atomic.stderr => rwlock_mutex_atomic.stderr} (51%) rename tests/ui/{mutex_atomic_unfixable.rs => rwlock_mutex_atomic_unfixable.rs} (100%) rename tests/ui/{mutex_atomic_unfixable.stderr => rwlock_mutex_atomic_unfixable.stderr} (91%) diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 7342066dbecc..707c27ec5556 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -535,8 +535,6 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::mut_key::MUTABLE_KEY_TYPE_INFO, crate::mut_mut::MUT_MUT_INFO, crate::mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL_INFO, - crate::mutex_atomic::MUTEX_ATOMIC_INFO, - crate::mutex_atomic::MUTEX_INTEGER_INFO, crate::needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE_INFO, crate::needless_bool::NEEDLESS_BOOL_INFO, crate::needless_bool::NEEDLESS_BOOL_ASSIGN_INFO, @@ -666,8 +664,10 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::returns::LET_AND_RETURN_INFO, crate::returns::NEEDLESS_RETURN_INFO, crate::returns::NEEDLESS_RETURN_WITH_QUESTION_MARK_INFO, - crate::rwlock_atomic::RWLOCK_ATOMIC_INFO, - crate::rwlock_atomic::RWLOCK_INTEGER_INFO, + crate::rwlock_mutex_atomic::MUTEX_ATOMIC_INFO, + crate::rwlock_mutex_atomic::MUTEX_INTEGER_INFO, + crate::rwlock_mutex_atomic::RWLOCK_ATOMIC_INFO, + crate::rwlock_mutex_atomic::RWLOCK_INTEGER_INFO, crate::same_name_method::SAME_NAME_METHOD_INFO, crate::self_named_constructors::SELF_NAMED_CONSTRUCTORS_INFO, crate::semicolon_block::SEMICOLON_INSIDE_BLOCK_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index d6c95ed4e670..be7d74c368fe 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -242,7 +242,6 @@ mod multiple_unsafe_ops_per_block; mod mut_key; mod mut_mut; mod mutable_debug_assertion; -mod mutex_atomic; mod needless_arbitrary_self_type; mod needless_bool; mod needless_borrowed_ref; @@ -317,7 +316,7 @@ mod replace_box; mod reserve_after_initialization; mod return_self_not_must_use; mod returns; -mod rwlock_atomic; +mod rwlock_mutex_atomic; mod same_name_method; mod self_named_constructors; mod semicolon_block; @@ -585,7 +584,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co Box::new(|_| Box::new(entry::HashMapPass)), Box::new(|_| Box::new(minmax::MinMaxPass)), Box::new(|_| Box::new(zero_div_zero::ZeroDiv)), - Box::new(|_| Box::new(mutex_atomic::Mutex)), + Box::new(|_| Box::new(rwlock_mutex_atomic::SyncGuard)), Box::new(|_| Box::new(needless_update::NeedlessUpdate)), Box::new(|_| Box::new(needless_borrowed_ref::NeedlessBorrowedRef)), Box::new(|_| Box::new(borrow_deref_ref::BorrowDerefRef)), @@ -851,7 +850,6 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co Box::new(|_| Box::new(volatile_composites::VolatileComposites)), Box::new(|_| Box::::default()), Box::new(move |_| Box::new(manual_ilog2::ManualIlog2::new(conf))), - Box::new(|_| Box::new(rwlock_atomic::RwLock)), // add late passes here, used by `cargo dev new_lint` ]; store.late_passes.extend(late_lints); diff --git a/clippy_lints/src/rwlock_atomic.rs b/clippy_lints/src/rwlock_atomic.rs deleted file mode 100644 index 4e7994abe344..000000000000 --- a/clippy_lints/src/rwlock_atomic.rs +++ /dev/null @@ -1,176 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::res::MaybeDef; -use clippy_utils::source::{IntoSpan, SpanRangeExt}; -use clippy_utils::sugg::Sugg; -use clippy_utils::ty::ty_from_hir_ty; -use rustc_errors::{Applicability, Diag}; -use rustc_hir::{self as hir, Expr, ExprKind, Item, ItemKind, LetStmt, QPath}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::mir::Mutability; -use rustc_middle::ty::{self, IntTy, Ty, UintTy}; -use rustc_session::declare_lint_pass; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// Checks for usage of `RwLock` where an atomic will do. - /// - /// ### Why is this bad? - /// Using a RwLock just to make access to a plain bool or - /// reference sequential is shooting flies with cannons. - /// `std::sync::atomic::AtomicBool` and `std::sync::atomic::AtomicPtr` are leaner and - /// faster. - /// - /// On the other hand, `RwLock`s are, in general, easier to - /// verify correctness. An atomic does not behave the same as - /// an equivalent RwLock. - /// - /// ### Example - /// ```no_run - /// # let y = true; - /// # use std::sync::RwLock; - /// let x = RwLock::new(&y); - /// ``` - /// - /// Use instead: - /// ```no_run - /// # let y = true; - /// # use std::sync::atomic::AtomicBool; - /// let x = AtomicBool::new(y); - /// ``` - #[clippy::version = "1.93.0"] - pub RWLOCK_ATOMIC, - restriction, - "using a RwLock where an atomic value could be used instead." -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for usage of `RwLock` where `X` is an integral - /// type. - /// - /// ### Why is this bad? - /// Using a RwLock just to make access to a plain integer - /// sequential is - /// shooting flies with cannons. `std::sync::atomic::AtomicUsize` is leaner and faster. - /// - /// On the other hand, `RwLock`s are, in general, easier to - /// verify correctness. An atomic does not behave the same as - /// an equivalent RwLock. - /// - /// ### Example - /// ```no_run - /// # use std::sync::RwLock; - /// let x = RwLock::new(0usize); - /// ``` - /// - /// Use instead: - /// ```no_run - /// # use std::sync::atomic::AtomicUsize; - /// let x = AtomicUsize::new(0usize); - /// ``` - #[clippy::version = "1.93.0"] - pub RWLOCK_INTEGER, - restriction, - "using a RwLock for an integer type" -} - -declare_lint_pass!(RwLock => [RWLOCK_ATOMIC, RWLOCK_INTEGER]); - -impl<'tcx> LateLintPass<'tcx> for RwLock { - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if !item.span.from_expansion() - && let ItemKind::Static(_, _, ty, body_id) = item.kind - { - let body = cx.tcx.hir_body(body_id); - let mid_ty = ty_from_hir_ty(cx, ty); - check_expr(cx, body.value.peel_blocks(), &TypeAscriptionKind::Required(ty), mid_ty); - } - } - fn check_local(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx LetStmt<'_>) { - if !stmt.span.from_expansion() - && let Some(init) = stmt.init - { - let mid_ty = cx.typeck_results().expr_ty(init); - check_expr(cx, init.peel_blocks(), &TypeAscriptionKind::Optional(stmt.ty), mid_ty); - } - } -} - -enum TypeAscriptionKind<'tcx> { - Required(&'tcx hir::Ty<'tcx>), - Optional(Option<&'tcx hir::Ty<'tcx>>), -} - -fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, ty_ascription: &TypeAscriptionKind<'tcx>, ty: Ty<'tcx>) { - if let ty::Adt(_, subst) = ty.kind() - && ty.is_diag_item(cx, sym::RwLock) - && let rwlock_param = subst.type_at(0) - && let Some(atomic_name) = get_atomic_name(rwlock_param) - { - let msg = "using a `RwLock` where an atomic would do"; - let diag = |diag: &mut Diag<'_, _>| { - if let ExprKind::Call(qpath, [arg]) = expr.kind - && let ExprKind::Path(QPath::TypeRelative(_rwlock, new)) = qpath.kind - && new.ident.name == sym::new - { - let mut applicability = Applicability::MaybeIncorrect; - let arg = Sugg::hir_with_applicability(cx, arg, "_", &mut applicability); - let mut suggs = vec![(expr.span, format!("std::sync::atomic::{atomic_name}::new({arg})"))]; - match ty_ascription { - TypeAscriptionKind::Required(ty_ascription) => { - suggs.push((ty_ascription.span, format!("std::sync::atomic::{atomic_name}"))); - }, - TypeAscriptionKind::Optional(Some(ty_ascription)) => { - let colon_ascription = (cx.sess().source_map()) - .span_extend_to_prev_char_before(ty_ascription.span, ':', true) - .with_leading_whitespace(cx) - .into_span(); - suggs.push((colon_ascription, String::new())); - }, - TypeAscriptionKind::Optional(None) => {}, - } - diag.multipart_suggestion("try", suggs, applicability); - } else { - diag.help(format!("consider using an `{atomic_name}` instead")); - } - diag.help("if you just want the locking behavior and not the internal type, consider using `RwLock<()>`"); - }; - match *rwlock_param.kind() { - ty::Uint(t) if t != UintTy::Usize => span_lint_and_then(cx, RWLOCK_INTEGER, expr.span, msg, diag), - ty::Int(t) if t != IntTy::Isize => span_lint_and_then(cx, RWLOCK_INTEGER, expr.span, msg, diag), - _ => span_lint_and_then(cx, RWLOCK_ATOMIC, expr.span, msg, diag), - } - } -} - -fn get_atomic_name(ty: Ty<'_>) -> Option<&'static str> { - match ty.kind() { - ty::Bool => Some("AtomicBool"), - ty::Uint(uint_ty) => { - match uint_ty { - UintTy::U8 => Some("AtomicU8"), - UintTy::U16 => Some("AtomicU16"), - UintTy::U32 => Some("AtomicU32"), - UintTy::U64 => Some("AtomicU64"), - UintTy::Usize => Some("AtomicUsize"), - // `AtomicU128` is unstable and only available on a few platforms: https://github.com/rust-lang/rust/issues/99069 - UintTy::U128 => None, - } - }, - ty::Int(int_ty) => { - match int_ty { - IntTy::I8 => Some("AtomicI8"), - IntTy::I16 => Some("AtomicI16"), - IntTy::I32 => Some("AtomicI32"), - IntTy::I64 => Some("AtomicI64"), - IntTy::Isize => Some("AtomicIsize"), - // `AtomicU128` is unstable and only available on a few platforms: https://github.com/rust-lang/rust/issues/99069 - IntTy::I128 => None, - } - }, - // `AtomicPtr` only accepts `*mut T` - ty::RawPtr(_, Mutability::Mut) => Some("AtomicPtr"), - _ => None, - } -} diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/rwlock_mutex_atomic.rs similarity index 72% rename from clippy_lints/src/mutex_atomic.rs rename to clippy_lints/src/rwlock_mutex_atomic.rs index 2fef8404f824..ec5a26e7756a 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/rwlock_mutex_atomic.rs @@ -11,6 +11,70 @@ use rustc_middle::ty::{self, IntTy, Ty, UintTy}; use rustc_session::declare_lint_pass; use rustc_span::sym; +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `RwLock` where an atomic will do. + /// + /// ### Why is this bad? + /// Using a RwLock just to make access to a plain bool or + /// reference sequential is shooting flies with cannons. + /// `std::sync::atomic::AtomicBool` and `std::sync::atomic::AtomicPtr` are leaner and + /// faster. + /// + /// On the other hand, `RwLock`s are, in general, easier to reason about + /// and to verify for correctness. Atomics do not provide the same + /// synchronization semantics as an equivalent `RwLock`. + /// + /// ### Example + /// ```no_run + /// # let y = true; + /// # use std::sync::RwLock; + /// let x = RwLock::new(&y); + /// ``` + /// + /// Use instead: + /// ```no_run + /// # let y = true; + /// # use std::sync::atomic::AtomicBool; + /// let x = AtomicBool::new(y); + /// ``` + #[clippy::version = "1.93.0"] + pub RWLOCK_ATOMIC, + restriction, + "using a RwLock where an atomic value could be used instead." +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `RwLock` where `X` is an integral + /// type. + /// + /// ### Why is this bad? + /// Using a RwLock just to make access to a plain integer + /// sequential is + /// shooting flies with cannons. `std::sync::atomic::AtomicUsize` is leaner and faster. + /// + /// On the other hand, `RwLock`s are, in general, easier to reason about + /// and to verify for correctness. Atomics do not provide the same + /// synchronization semantics as an equivalent `RwLock`. + /// + /// ### Example + /// ```no_run + /// # use std::sync::RwLock; + /// let x = RwLock::new(0usize); + /// ``` + /// + /// Use instead: + /// ```no_run + /// # use std::sync::atomic::AtomicUsize; + /// let x = AtomicUsize::new(0usize); + /// ``` + #[clippy::version = "1.93.0"] + pub RWLOCK_INTEGER, + restriction, + "using a RwLock for an integer type" +} + declare_clippy_lint! { /// ### What it does /// Checks for usage of `Mutex` where an atomic will do. @@ -91,11 +155,16 @@ declare_clippy_lint! { "using a mutex for an integer type" } -declare_lint_pass!(Mutex => [MUTEX_ATOMIC, MUTEX_INTEGER]); +declare_lint_pass!(SyncGuard => [ + RWLOCK_ATOMIC, + RWLOCK_INTEGER, + MUTEX_ATOMIC, + MUTEX_INTEGER +]); // NOTE: we don't use `check_expr` because that would make us lint every _use_ of such mutexes, not // just their definitions -impl<'tcx> LateLintPass<'tcx> for Mutex { +impl<'tcx> LateLintPass<'tcx> for SyncGuard { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if !item.span.from_expansion() && let ItemKind::Static(_, _, ty, body_id) = item.kind @@ -123,6 +192,8 @@ enum TypeAscriptionKind<'tcx> { /// No; the ascription might've been necessary in an expression like: /// ```ignore /// let mutex: Mutex = Mutex::new(0); + /// // Or + /// let rwlock: RwLock = RwLock::new(0); /// ``` /// to specify the type of `0`, but since `AtomicX` already refers to a concrete type, we won't /// need this ascription anymore. @@ -131,13 +202,23 @@ enum TypeAscriptionKind<'tcx> { fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, ty_ascription: &TypeAscriptionKind<'tcx>, ty: Ty<'tcx>) { if let ty::Adt(_, subst) = ty.kind() - && ty.is_diag_item(cx, sym::Mutex) + && let Some((lock_name, lint_integer, lint_atomic)) = if ty.is_diag_item(cx, sym::Mutex) { + Some(("Mutex", MUTEX_INTEGER, MUTEX_ATOMIC)) + } else if ty.is_diag_item(cx, sym::RwLock) { + Some(("RwLock", RWLOCK_INTEGER, RWLOCK_ATOMIC)) + } else { + None + } && let mutex_param = subst.type_at(0) && let Some(atomic_name) = get_atomic_name(mutex_param) { - let msg = "using a `Mutex` where an atomic would do"; + let msg: &str = if lock_name == "Mutex" { + "using a `Mutex` where an atomic would do" + } else { + "using a `RwLock` where an atomic would do" + }; let diag = |diag: &mut Diag<'_, _>| { - // if `expr = Mutex::new(arg)`, we can try emitting a suggestion + // if `expr = Mutex::new(arg)` or `expr = RwLock::new(arg)`, we can try emitting a suggestion if let ExprKind::Call(qpath, [arg]) = expr.kind && let ExprKind::Path(QPath::TypeRelative(_mutex, new)) = qpath.kind && new.ident.name == sym::new @@ -164,12 +245,14 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, ty_ascription: &T } else { diag.help(format!("consider using an `{atomic_name}` instead")); } - diag.help("if you just want the locking behavior and not the internal type, consider using `Mutex<()>`"); + diag.help(format!( + "if you just want the locking behavior and not the internal type, consider using `{lock_name}<()>`" + )); }; match *mutex_param.kind() { - ty::Uint(t) if t != UintTy::Usize => span_lint_and_then(cx, MUTEX_INTEGER, expr.span, msg, diag), - ty::Int(t) if t != IntTy::Isize => span_lint_and_then(cx, MUTEX_INTEGER, expr.span, msg, diag), - _ => span_lint_and_then(cx, MUTEX_ATOMIC, expr.span, msg, diag), + ty::Uint(t) if t != UintTy::Usize => span_lint_and_then(cx, lint_integer, expr.span, msg, diag), + ty::Int(t) if t != IntTy::Isize => span_lint_and_then(cx, lint_integer, expr.span, msg, diag), + _ => span_lint_and_then(cx, lint_atomic, expr.span, msg, diag), } } } diff --git a/tests/ui/rwlock_atomic.fixed b/tests/ui/rwlock_atomic.fixed deleted file mode 100644 index 24cdc3127e24..000000000000 --- a/tests/ui/rwlock_atomic.fixed +++ /dev/null @@ -1,49 +0,0 @@ -#![warn(clippy::rwlock_integer)] -#![warn(clippy::rwlock_atomic)] -#![allow(clippy::borrow_as_ptr)] - -use std::sync::RwLock; - -fn main() { - let _ = std::sync::atomic::AtomicBool::new(true); - //~^ rwlock_atomic - - let _ = std::sync::atomic::AtomicUsize::new(5usize); - //~^ rwlock_atomic - - let _ = std::sync::atomic::AtomicIsize::new(9isize); - //~^ rwlock_atomic - - let mut x = 4u32; - // `AtomicPtr` only accepts `*mut T`, so this should not lint - let _ = RwLock::new(&x as *const u32); - - let _ = std::sync::atomic::AtomicPtr::new(&mut x as *mut u32); - //~^ rwlock_atomic - - let _ = std::sync::atomic::AtomicU32::new(0u32); - //~^ rwlock_integer - - let _ = std::sync::atomic::AtomicI32::new(0i32); - //~^ rwlock_integer - - let _ = RwLock::new(0f32); // there are no float atomics, so this should not lint - let _ = std::sync::atomic::AtomicU8::new(0u8); - //~^ rwlock_integer - - let _ = std::sync::atomic::AtomicI16::new(0i16); - //~^ rwlock_integer - - let _x = std::sync::atomic::AtomicI8::new(0); - //~^ rwlock_integer - - const X: i64 = 0; - let _ = std::sync::atomic::AtomicI64::new(X); - //~^ rwlock_integer - - // there are no 128 atomics, so these two should not lint - { - let _ = RwLock::new(0u128); - let _x: RwLock = RwLock::new(0); - } -} diff --git a/tests/ui/rwlock_atomic.rs b/tests/ui/rwlock_atomic.rs deleted file mode 100644 index 51bc775a9e38..000000000000 --- a/tests/ui/rwlock_atomic.rs +++ /dev/null @@ -1,49 +0,0 @@ -#![warn(clippy::rwlock_integer)] -#![warn(clippy::rwlock_atomic)] -#![allow(clippy::borrow_as_ptr)] - -use std::sync::RwLock; - -fn main() { - let _ = RwLock::new(true); - //~^ rwlock_atomic - - let _ = RwLock::new(5usize); - //~^ rwlock_atomic - - let _ = RwLock::new(9isize); - //~^ rwlock_atomic - - let mut x = 4u32; - // `AtomicPtr` only accepts `*mut T`, so this should not lint - let _ = RwLock::new(&x as *const u32); - - let _ = RwLock::new(&mut x as *mut u32); - //~^ rwlock_atomic - - let _ = RwLock::new(0u32); - //~^ rwlock_integer - - let _ = RwLock::new(0i32); - //~^ rwlock_integer - - let _ = RwLock::new(0f32); // there are no float atomics, so this should not lint - let _ = RwLock::new(0u8); - //~^ rwlock_integer - - let _ = RwLock::new(0i16); - //~^ rwlock_integer - - let _x: RwLock = RwLock::new(0); - //~^ rwlock_integer - - const X: i64 = 0; - let _ = RwLock::new(X); - //~^ rwlock_integer - - // there are no 128 atomics, so these two should not lint - { - let _ = RwLock::new(0u128); - let _x: RwLock = RwLock::new(0); - } -} diff --git a/tests/ui/rwlock_atomic.stderr b/tests/ui/rwlock_atomic.stderr deleted file mode 100644 index da2cd2bbb619..000000000000 --- a/tests/ui/rwlock_atomic.stderr +++ /dev/null @@ -1,91 +0,0 @@ -error: using a `RwLock` where an atomic would do - --> tests/ui/rwlock_atomic.rs:8:13 - | -LL | let _ = RwLock::new(true); - | ^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicBool::new(true)` - | - = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` - = note: `-D clippy::rwlock-atomic` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::rwlock_atomic)]` - -error: using a `RwLock` where an atomic would do - --> tests/ui/rwlock_atomic.rs:11:13 - | -LL | let _ = RwLock::new(5usize); - | ^^^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicUsize::new(5usize)` - | - = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` - -error: using a `RwLock` where an atomic would do - --> tests/ui/rwlock_atomic.rs:14:13 - | -LL | let _ = RwLock::new(9isize); - | ^^^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicIsize::new(9isize)` - | - = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` - -error: using a `RwLock` where an atomic would do - --> tests/ui/rwlock_atomic.rs:21:13 - | -LL | let _ = RwLock::new(&mut x as *mut u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicPtr::new(&mut x as *mut u32)` - | - = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` - -error: using a `RwLock` where an atomic would do - --> tests/ui/rwlock_atomic.rs:24:13 - | -LL | let _ = RwLock::new(0u32); - | ^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicU32::new(0u32)` - | - = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` - = note: `-D clippy::rwlock-integer` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::rwlock_integer)]` - -error: using a `RwLock` where an atomic would do - --> tests/ui/rwlock_atomic.rs:27:13 - | -LL | let _ = RwLock::new(0i32); - | ^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI32::new(0i32)` - | - = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` - -error: using a `RwLock` where an atomic would do - --> tests/ui/rwlock_atomic.rs:31:13 - | -LL | let _ = RwLock::new(0u8); - | ^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicU8::new(0u8)` - | - = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` - -error: using a `RwLock` where an atomic would do - --> tests/ui/rwlock_atomic.rs:34:13 - | -LL | let _ = RwLock::new(0i16); - | ^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI16::new(0i16)` - | - = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` - -error: using a `RwLock` where an atomic would do - --> tests/ui/rwlock_atomic.rs:37:26 - | -LL | let _x: RwLock = RwLock::new(0); - | ^^^^^^^^^^^^^^ - | - = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` -help: try - | -LL - let _x: RwLock = RwLock::new(0); -LL + let _x = std::sync::atomic::AtomicI8::new(0); - | - -error: using a `RwLock` where an atomic would do - --> tests/ui/rwlock_atomic.rs:41:13 - | -LL | let _ = RwLock::new(X); - | ^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI64::new(X)` - | - = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` - -error: aborting due to 10 previous errors - diff --git a/tests/ui/mutex_atomic.fixed b/tests/ui/rwlock_mutex_atomic.fixed similarity index 59% rename from tests/ui/mutex_atomic.fixed rename to tests/ui/rwlock_mutex_atomic.fixed index e4218726019f..623d25a96bc2 100644 --- a/tests/ui/mutex_atomic.fixed +++ b/tests/ui/rwlock_mutex_atomic.fixed @@ -1,49 +1,75 @@ +#![warn(clippy::rwlock_integer)] +#![warn(clippy::rwlock_atomic)] #![warn(clippy::mutex_integer)] #![warn(clippy::mutex_atomic)] #![allow(clippy::borrow_as_ptr)] -use std::sync::Mutex; +use std::sync::{Mutex, RwLock}; fn main() { + let _ = std::sync::atomic::AtomicBool::new(true); + //~^ rwlock_atomic let _ = std::sync::atomic::AtomicBool::new(true); //~^ mutex_atomic + let _ = std::sync::atomic::AtomicUsize::new(5usize); + //~^ rwlock_atomic let _ = std::sync::atomic::AtomicUsize::new(5usize); //~^ mutex_atomic + let _ = std::sync::atomic::AtomicIsize::new(9isize); + //~^ rwlock_atomic let _ = std::sync::atomic::AtomicIsize::new(9isize); //~^ mutex_atomic let mut x = 4u32; - // `AtomicPtr` only accepts `*mut T`, so this should not lint + // `AtomicPtr` only accepts `*mut T`, so these should not lint + let _ = RwLock::new(&x as *const u32); let _ = Mutex::new(&x as *const u32); + let _ = std::sync::atomic::AtomicPtr::new(&mut x as *mut u32); + //~^ rwlock_atomic let _ = std::sync::atomic::AtomicPtr::new(&mut x as *mut u32); //~^ mutex_atomic + let _ = std::sync::atomic::AtomicU32::new(0u32); + //~^ rwlock_integer let _ = std::sync::atomic::AtomicU32::new(0u32); //~^ mutex_integer + let _ = std::sync::atomic::AtomicI32::new(0i32); + //~^ rwlock_integer let _ = std::sync::atomic::AtomicI32::new(0i32); //~^ mutex_integer + let _ = RwLock::new(0f32); // there are no float atomics, so this should not lint + let _ = std::sync::atomic::AtomicU8::new(0u8); + //~^ rwlock_integer let _ = Mutex::new(0f32); // there are no float atomics, so this should not lint let _ = std::sync::atomic::AtomicU8::new(0u8); //~^ mutex_integer + let _ = std::sync::atomic::AtomicI16::new(0i16); + //~^ rwlock_integer let _ = std::sync::atomic::AtomicI16::new(0i16); //~^ mutex_integer + let _x = std::sync::atomic::AtomicI8::new(0); + //~^ rwlock_integer let _x = std::sync::atomic::AtomicI8::new(0); //~^ mutex_integer const X: i64 = 0; let _ = std::sync::atomic::AtomicI64::new(X); + //~^ rwlock_integer + let _ = std::sync::atomic::AtomicI64::new(X); //~^ mutex_integer - // there are no 128 atomics, so these two should not lint + // there are no 128 atomics, so these four should not lint { + let _ = RwLock::new(0u128); let _ = Mutex::new(0u128); + let _x: RwLock = RwLock::new(0); let _x: Mutex = Mutex::new(0); } } diff --git a/tests/ui/mutex_atomic.rs b/tests/ui/rwlock_mutex_atomic.rs similarity index 60% rename from tests/ui/mutex_atomic.rs rename to tests/ui/rwlock_mutex_atomic.rs index 95f2b135903f..790132d422cc 100644 --- a/tests/ui/mutex_atomic.rs +++ b/tests/ui/rwlock_mutex_atomic.rs @@ -1,49 +1,75 @@ +#![warn(clippy::rwlock_integer)] +#![warn(clippy::rwlock_atomic)] #![warn(clippy::mutex_integer)] #![warn(clippy::mutex_atomic)] #![allow(clippy::borrow_as_ptr)] -use std::sync::Mutex; +use std::sync::{Mutex, RwLock}; fn main() { + let _ = RwLock::new(true); + //~^ rwlock_atomic let _ = Mutex::new(true); //~^ mutex_atomic + let _ = RwLock::new(5usize); + //~^ rwlock_atomic let _ = Mutex::new(5usize); //~^ mutex_atomic + let _ = RwLock::new(9isize); + //~^ rwlock_atomic let _ = Mutex::new(9isize); //~^ mutex_atomic let mut x = 4u32; - // `AtomicPtr` only accepts `*mut T`, so this should not lint + // `AtomicPtr` only accepts `*mut T`, so these should not lint + let _ = RwLock::new(&x as *const u32); let _ = Mutex::new(&x as *const u32); + let _ = RwLock::new(&mut x as *mut u32); + //~^ rwlock_atomic let _ = Mutex::new(&mut x as *mut u32); //~^ mutex_atomic + let _ = RwLock::new(0u32); + //~^ rwlock_integer let _ = Mutex::new(0u32); //~^ mutex_integer + let _ = RwLock::new(0i32); + //~^ rwlock_integer let _ = Mutex::new(0i32); //~^ mutex_integer + let _ = RwLock::new(0f32); // there are no float atomics, so this should not lint + let _ = RwLock::new(0u8); + //~^ rwlock_integer let _ = Mutex::new(0f32); // there are no float atomics, so this should not lint let _ = Mutex::new(0u8); //~^ mutex_integer + let _ = RwLock::new(0i16); + //~^ rwlock_integer let _ = Mutex::new(0i16); //~^ mutex_integer + let _x: RwLock = RwLock::new(0); + //~^ rwlock_integer let _x: Mutex = Mutex::new(0); //~^ mutex_integer const X: i64 = 0; + let _ = RwLock::new(X); + //~^ rwlock_integer let _ = Mutex::new(X); //~^ mutex_integer - // there are no 128 atomics, so these two should not lint + // there are no 128 atomics, so these four should not lint { + let _ = RwLock::new(0u128); let _ = Mutex::new(0u128); + let _x: RwLock = RwLock::new(0); let _x: Mutex = Mutex::new(0); } } diff --git a/tests/ui/mutex_atomic.stderr b/tests/ui/rwlock_mutex_atomic.stderr similarity index 51% rename from tests/ui/mutex_atomic.stderr rename to tests/ui/rwlock_mutex_atomic.stderr index 0afc6d541dea..cedc422066a1 100644 --- a/tests/ui/mutex_atomic.stderr +++ b/tests/ui/rwlock_mutex_atomic.stderr @@ -1,5 +1,15 @@ +error: using a `RwLock` where an atomic would do + --> tests/ui/rwlock_mutex_atomic.rs:10:13 + | +LL | let _ = RwLock::new(true); + | ^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicBool::new(true)` + | + = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` + = note: `-D clippy::rwlock-atomic` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::rwlock_atomic)]` + error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:8:13 + --> tests/ui/rwlock_mutex_atomic.rs:12:13 | LL | let _ = Mutex::new(true); | ^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicBool::new(true)` @@ -8,32 +18,66 @@ LL | let _ = Mutex::new(true); = note: `-D clippy::mutex-atomic` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::mutex_atomic)]` +error: using a `RwLock` where an atomic would do + --> tests/ui/rwlock_mutex_atomic.rs:15:13 + | +LL | let _ = RwLock::new(5usize); + | ^^^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicUsize::new(5usize)` + | + = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` + error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:11:13 + --> tests/ui/rwlock_mutex_atomic.rs:17:13 | LL | let _ = Mutex::new(5usize); | ^^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicUsize::new(5usize)` | = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>` +error: using a `RwLock` where an atomic would do + --> tests/ui/rwlock_mutex_atomic.rs:20:13 + | +LL | let _ = RwLock::new(9isize); + | ^^^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicIsize::new(9isize)` + | + = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` + error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:14:13 + --> tests/ui/rwlock_mutex_atomic.rs:22:13 | LL | let _ = Mutex::new(9isize); | ^^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicIsize::new(9isize)` | = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>` +error: using a `RwLock` where an atomic would do + --> tests/ui/rwlock_mutex_atomic.rs:30:13 + | +LL | let _ = RwLock::new(&mut x as *mut u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicPtr::new(&mut x as *mut u32)` + | + = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` + error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:21:13 + --> tests/ui/rwlock_mutex_atomic.rs:32:13 | LL | let _ = Mutex::new(&mut x as *mut u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicPtr::new(&mut x as *mut u32)` | = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>` +error: using a `RwLock` where an atomic would do + --> tests/ui/rwlock_mutex_atomic.rs:35:13 + | +LL | let _ = RwLock::new(0u32); + | ^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicU32::new(0u32)` + | + = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` + = note: `-D clippy::rwlock-integer` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::rwlock_integer)]` + error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:24:13 + --> tests/ui/rwlock_mutex_atomic.rs:37:13 | LL | let _ = Mutex::new(0u32); | ^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicU32::new(0u32)` @@ -42,32 +86,69 @@ LL | let _ = Mutex::new(0u32); = note: `-D clippy::mutex-integer` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::mutex_integer)]` +error: using a `RwLock` where an atomic would do + --> tests/ui/rwlock_mutex_atomic.rs:40:13 + | +LL | let _ = RwLock::new(0i32); + | ^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI32::new(0i32)` + | + = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` + error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:27:13 + --> tests/ui/rwlock_mutex_atomic.rs:42:13 | LL | let _ = Mutex::new(0i32); | ^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI32::new(0i32)` | = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>` +error: using a `RwLock` where an atomic would do + --> tests/ui/rwlock_mutex_atomic.rs:46:13 + | +LL | let _ = RwLock::new(0u8); + | ^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicU8::new(0u8)` + | + = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` + error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:31:13 + --> tests/ui/rwlock_mutex_atomic.rs:49:13 | LL | let _ = Mutex::new(0u8); | ^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicU8::new(0u8)` | = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>` +error: using a `RwLock` where an atomic would do + --> tests/ui/rwlock_mutex_atomic.rs:52:13 + | +LL | let _ = RwLock::new(0i16); + | ^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI16::new(0i16)` + | + = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` + error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:34:13 + --> tests/ui/rwlock_mutex_atomic.rs:54:13 | LL | let _ = Mutex::new(0i16); | ^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI16::new(0i16)` | = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>` +error: using a `RwLock` where an atomic would do + --> tests/ui/rwlock_mutex_atomic.rs:57:26 + | +LL | let _x: RwLock = RwLock::new(0); + | ^^^^^^^^^^^^^^ + | + = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` +help: try + | +LL - let _x: RwLock = RwLock::new(0); +LL + let _x = std::sync::atomic::AtomicI8::new(0); + | + error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:37:25 + --> tests/ui/rwlock_mutex_atomic.rs:59:25 | LL | let _x: Mutex = Mutex::new(0); | ^^^^^^^^^^^^^ @@ -79,8 +160,16 @@ LL - let _x: Mutex = Mutex::new(0); LL + let _x = std::sync::atomic::AtomicI8::new(0); | +error: using a `RwLock` where an atomic would do + --> tests/ui/rwlock_mutex_atomic.rs:63:13 + | +LL | let _ = RwLock::new(X); + | ^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI64::new(X)` + | + = help: if you just want the locking behavior and not the internal type, consider using `RwLock<()>` + error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:41:13 + --> tests/ui/rwlock_mutex_atomic.rs:65:13 | LL | let _ = Mutex::new(X); | ^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI64::new(X)` @@ -88,7 +177,7 @@ LL | let _ = Mutex::new(X); = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>` error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:53:30 + --> tests/ui/rwlock_mutex_atomic.rs:79:30 | LL | static MTX: Mutex = Mutex::new(0); | ^^^^^^^^^^^^^ @@ -101,7 +190,7 @@ LL + static MTX: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32 | error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:56:15 + --> tests/ui/rwlock_mutex_atomic.rs:82:15 | LL | let mtx = Mutex::new(0); | ^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI32::new(0)` @@ -109,7 +198,7 @@ LL | let mtx = Mutex::new(0); = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>` error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:60:22 + --> tests/ui/rwlock_mutex_atomic.rs:86:22 | LL | let reassigned = mtx; | ^^^ @@ -118,7 +207,7 @@ LL | let reassigned = mtx; = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>` error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic.rs:65:35 + --> tests/ui/rwlock_mutex_atomic.rs:91:35 | LL | let (funky_mtx): Mutex = Mutex::new(0); | ^^^^^^^^^^^^^ @@ -130,5 +219,5 @@ LL - let (funky_mtx): Mutex = Mutex::new(0); LL + let (funky_mtx) = std::sync::atomic::AtomicU64::new(0); | -error: aborting due to 14 previous errors +error: aborting due to 24 previous errors diff --git a/tests/ui/mutex_atomic_unfixable.rs b/tests/ui/rwlock_mutex_atomic_unfixable.rs similarity index 100% rename from tests/ui/mutex_atomic_unfixable.rs rename to tests/ui/rwlock_mutex_atomic_unfixable.rs diff --git a/tests/ui/mutex_atomic_unfixable.stderr b/tests/ui/rwlock_mutex_atomic_unfixable.stderr similarity index 91% rename from tests/ui/mutex_atomic_unfixable.stderr rename to tests/ui/rwlock_mutex_atomic_unfixable.stderr index 27ffb1304c69..785b0b0dcf19 100644 --- a/tests/ui/mutex_atomic_unfixable.stderr +++ b/tests/ui/rwlock_mutex_atomic_unfixable.stderr @@ -1,5 +1,5 @@ error: using a `Mutex` where an atomic would do - --> tests/ui/mutex_atomic_unfixable.rs:7:30 + --> tests/ui/rwlock_mutex_atomic_unfixable.rs:7:30 | LL | static MTX: Mutex = Mutex::new(0); | ^^^^^^^^^^^^^