diff --git a/CHANGELOG.md b/CHANGELOG.md index d7bcd7a19687..be2fd64ff3da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5820,6 +5820,7 @@ Released 2018-09-13 [`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next [`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization [`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive +[`static_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#static_mut [`std_instead_of_alloc`]: https://rust-lang.github.io/rust-clippy/master/index.html#std_instead_of_alloc [`std_instead_of_core`]: https://rust-lang.github.io/rust-clippy/master/index.html#std_instead_of_core [`str_split_at_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_split_at_newline diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 7e43a99e9f24..a564a104c170 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -652,6 +652,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT_INFO, crate::size_of_ref::SIZE_OF_REF_INFO, crate::slow_vector_initialization::SLOW_VECTOR_INITIALIZATION_INFO, + crate::static_mut::STATIC_MUT_INFO, crate::std_instead_of_core::ALLOC_INSTEAD_OF_CORE_INFO, crate::std_instead_of_core::STD_INSTEAD_OF_ALLOC_INFO, crate::std_instead_of_core::STD_INSTEAD_OF_CORE_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c65581d5203e..1a42a1215d67 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -325,6 +325,7 @@ mod single_range_in_vec_init; mod size_of_in_element_count; mod size_of_ref; mod slow_vector_initialization; +mod static_mut; mod std_instead_of_core; mod string_patterns; mod strings; @@ -1169,6 +1170,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { }) }); store.register_late_pass(|_| Box::new(string_patterns::StringPatterns)); + store.register_early_pass(|| Box::new(static_mut::StaticMut)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/static_mut.rs b/clippy_lints/src/static_mut.rs new file mode 100644 index 000000000000..26e6bad86106 --- /dev/null +++ b/clippy_lints/src/static_mut.rs @@ -0,0 +1,60 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use rustc_ast::ast::{Item, ItemKind, Mutability, StaticItem}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Produces warnings when a `static mut` is declared. + /// + /// ### Why is this bad? + /// `static mut` can [easily produce undefined behavior][1] and + /// [may be removed in the future][2]. + /// + /// ### Example + /// ```no_run + /// static mut GLOBAL_INT: u8 = 0; + /// ``` + /// Use instead: + /// ```no_run + /// use std::sync::RwLock; + /// + /// static GLOBAL_INT: RwLock = RwLock::new(0); + /// ``` + /// + /// [1]: https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-reference.html + /// [2]: https://github.com/rust-lang/rfcs/pull/3560 + #[clippy::version = "1.80.0"] + pub STATIC_MUT, + nursery, + "detect mutable static definitions" +} + +declare_lint_pass!(StaticMut => [STATIC_MUT]); + +impl EarlyLintPass for StaticMut { + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + if in_external_macro(cx.sess(), item.span) { + return; + }; + let ItemKind::Static(ref static_item_box) = item.kind else { + return; + }; + let StaticItem { + mutability: Mutability::Mut, + .. + } = static_item_box.as_ref() + else { + return; + }; + span_lint_and_help( + cx, + STATIC_MUT, + item.span, + "declaration of static mut", + None, + "remove the `mut` and use a type with interior mutibability that implements `Sync`, such as `std::sync::Mutex`", + ); + } +} diff --git a/tests/ui/static_mut.rs b/tests/ui/static_mut.rs new file mode 100644 index 000000000000..85e0a145b028 --- /dev/null +++ b/tests/ui/static_mut.rs @@ -0,0 +1,3 @@ +#![warn(clippy::static_mut)] + +static mut NUMBER: u8 = 3; diff --git a/tests/ui/static_mut.stderr b/tests/ui/static_mut.stderr new file mode 100644 index 000000000000..58ac4be783af --- /dev/null +++ b/tests/ui/static_mut.stderr @@ -0,0 +1,12 @@ +error: declaration of static mut + --> tests/ui/static_mut.rs:3:1 + | +LL | static mut NUMBER: u8 = 3; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove the `mut` and use a type with interior mutibability that implements `Sync`, such as `std::sync::Mutex` + = note: `-D clippy::static-mut` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::static_mut)]` + +error: aborting due to 1 previous error +