Skip to content

Commit d3dee47

Browse files
committed
Add static_mut_ref lint
1 parent 1d6f05f commit d3dee47

File tree

6 files changed

+124
-0
lines changed

6 files changed

+124
-0
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -4109,6 +4109,7 @@ dependencies = [
41094109
"rustc_feature",
41104110
"rustc_fluent_macro",
41114111
"rustc_hir",
4112+
"rustc_hir_pretty",
41124113
"rustc_index",
41134114
"rustc_infer",
41144115
"rustc_macros",

compiler/rustc_lint/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ rustc_errors = { path = "../rustc_errors" }
1313
rustc_feature = { path = "../rustc_feature" }
1414
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
1515
rustc_hir = { path = "../rustc_hir" }
16+
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
1617
rustc_index = { path = "../rustc_index" }
1718
rustc_infer = { path = "../rustc_infer" }
1819
rustc_macros = { path = "../rustc_macros" }

compiler/rustc_lint/messages.ftl

+7
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,13 @@ lint_requested_level = requested on the command line with `{$level} {$lint_name}
496496
497497
lint_span_use_eq_ctxt = use `.eq_ctxt()` instead of `.ctxt() == .ctxt()`
498498
499+
lint_static_mut_ref = use of mutable static is discouraged
500+
.label = use of mutable static
501+
.note = use of mutable static is a hard error from 2024 edition
502+
.suggestion = use `addr_of_mut!` macro
503+
504+
lint_static_mut_ref_why_note = mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
505+
499506
lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target
500507
.label = target type is set here
501508

compiler/rustc_lint/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ mod passes;
8383
mod ptr_nulls;
8484
mod redundant_semicolon;
8585
mod reference_casting;
86+
mod static_mut_ref;
8687
mod traits;
8788
mod types;
8889
mod unused;
@@ -121,6 +122,7 @@ use pass_by_value::*;
121122
use ptr_nulls::*;
122123
use redundant_semicolon::*;
123124
use reference_casting::*;
125+
use static_mut_ref::*;
124126
use traits::*;
125127
use types::*;
126128
use unused::*;
@@ -239,6 +241,7 @@ late_lint_methods!(
239241
MissingDebugImplementations: MissingDebugImplementations,
240242
MissingDoc: MissingDoc,
241243
AsyncFnInTrait: AsyncFnInTrait,
244+
StaticMutRef: StaticMutRef,
242245
]
243246
]
244247
);

compiler/rustc_lint/src/lints.rs

+17
Original file line numberDiff line numberDiff line change
@@ -1845,3 +1845,20 @@ impl<'a> DecorateLint<'a, ()> for AsyncFnInTraitDiag {
18451845
fluent::lint_async_fn_in_trait
18461846
}
18471847
}
1848+
1849+
// static_mut_ref.rs
1850+
#[derive(LintDiagnostic)]
1851+
#[diag(lint_static_mut_ref)]
1852+
#[note]
1853+
pub struct UseOfStaticMut {
1854+
#[label]
1855+
#[suggestion(
1856+
style = "verbose",
1857+
code = "addr_of_mut!({var})",
1858+
applicability = "maybe-incorrect"
1859+
)]
1860+
pub span: Span,
1861+
#[note(lint_static_mut_ref_why_note)]
1862+
pub why_note: (),
1863+
pub var: String,
1864+
}
+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
use crate::lints::UseOfStaticMut;
2+
use crate::{LateContext, LateLintPass, LintContext};
3+
use rustc_ast::BorrowKind;
4+
use rustc_hir::{
5+
def::{DefKind, Res::Def},
6+
intravisit::FnKind,
7+
Block, BlockCheckMode, Body, ExprKind, FnDecl, QPath, Stmt, StmtKind,
8+
UnsafeSource::UserProvided,
9+
Unsafety,
10+
};
11+
use rustc_hir_pretty::qpath_to_string;
12+
use rustc_span::{def_id::LocalDefId, Span};
13+
use rustc_type_ir::Mutability;
14+
15+
declare_lint! {
16+
/// The `static_mut_ref` lint checks for use of mutable static
17+
/// inside `unsafe` blocks and `unsafe` functions.
18+
///
19+
/// ### Example
20+
///
21+
/// ```rust,no_run
22+
/// fn main() {
23+
/// static mut X: i32 = 23;
24+
/// unsafe {
25+
/// let y = &X;
26+
/// }
27+
/// }
28+
///
29+
/// unsafe fn foo() {
30+
/// static mut X: i32 = 23;
31+
/// let y = &X;
32+
/// }
33+
/// ```
34+
///
35+
/// {{produces}}
36+
///
37+
/// ### Explanation
38+
///
39+
/// Use of mutable static is almost always a mistake and can lead to
40+
/// undefined behavior and various other problems in your code.
41+
///
42+
/// This lint is "warn" by default on editions up to 2021, from 2024 it is
43+
/// a hard error.
44+
pub STATIC_MUT_REF,
45+
Warn,
46+
"use of mutable static is discouraged"
47+
}
48+
49+
declare_lint_pass!(StaticMutRef => [STATIC_MUT_REF]);
50+
51+
impl<'tcx> LateLintPass<'tcx> for StaticMutRef {
52+
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
53+
if let BlockCheckMode::UnsafeBlock(src) = block.rules
54+
&& matches!(src, UserProvided)
55+
{
56+
check_stmts(cx, block.stmts);
57+
}
58+
}
59+
60+
fn check_fn(
61+
&mut self,
62+
cx: &LateContext<'tcx>,
63+
fn_kind: FnKind<'tcx>,
64+
_: &'tcx FnDecl<'tcx>,
65+
body: &'tcx Body<'tcx>,
66+
_: Span,
67+
_: LocalDefId,
68+
) {
69+
if let FnKind::ItemFn(_, _, h) = fn_kind
70+
&& matches!(h.unsafety, Unsafety::Unsafe)
71+
&& let ExprKind::Block(block, _) = body.value.kind
72+
{
73+
check_stmts(cx, block.stmts);
74+
}
75+
}
76+
}
77+
78+
fn check_stmts(cx: &LateContext<'_>, stmts: &[Stmt<'_>]) {
79+
for stmt in stmts.iter() {
80+
if let StmtKind::Local(loc) = stmt.kind
81+
&& let Some(init) = loc.init
82+
&& let ExprKind::AddrOf(borrow_kind, _, expr) = init.kind
83+
&& matches!(borrow_kind, BorrowKind::Ref)
84+
&& let ExprKind::Path(qpath) = expr.kind
85+
&& let QPath::Resolved(_, path) = qpath
86+
&& let Def(def_kind, _) = path.res
87+
&& let DefKind::Static(mt) = def_kind
88+
&& matches!(mt, Mutability::Mut)
89+
{
90+
let span = init.span;
91+
let var = qpath_to_string(&qpath);
92+
cx.emit_spanned_lint(STATIC_MUT_REF, span, UseOfStaticMut { span, why_note: (), var });
93+
}
94+
}
95+
}

0 commit comments

Comments
 (0)