-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add static_mut
lint
#12914
Add static_mut
lint
#12914
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -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<u8> = 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) { | ||||||
Comment on lines
+36
to
+37
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The issue mentioned some suggestions to replace There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The issue does mention |
||||||
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`", | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a pretty long text. Perhaps we might move some of it to the docs? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. my concern is that a lot of beginners won't know what "interior mutability" is without an example, and removing the qualification about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then perhaps we can move that into a help text, to keep the lint message short. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that is a help message, the actual lint message is just There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
); | ||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#![warn(clippy::static_mut)] | ||
|
||
static mut NUMBER: u8 = 3; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should extend the example to also show at least one of the
Atomic*
types, as well as possiblyLazy
or perhaps evenUnsafeCell
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
correctly using
Atomic*
is tricky, and i don't think we should be reccomending them to beginners.UnsafeCell
won't work, we needSyncUnsafeCell
, which isn't stable yet.LazyLock
andLazyCell
are both still unstable.OnceCell
is a decent option, however, it makes it pretty easy to introduce TOC-TOU bugs.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that all of these types have their pros and cons, yet just showing
RwLock
makes the docs woefully incomplete.How about at least listing the options with a short description of their niche and shortcomings? Such as:
std::sync::atomic::Atomic*
typeconst
and don't actually need to update later on, you can usestd::sync::Lazy
main
before starting any threads, you can usestd::cell::Once
std::cell::*Cell
types might work for you, but be aware that the other options avoid the unsafety, often without measurably affecting performance.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unless things have changed since i last checked, the type of a static must always implement
Sync
, which means most of these will never work. i suppose i could mention the atomic primatives, and maybeLazyLock
andUnsafeSyncCell
under a "if you're already using nightly" section.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::sync::Once
and thestd::sync::atomic
s do implementSync
last I checked. I'm on mobile now, so I won't check all of them, but that certainly gives us some options.