Skip to content

Commit 7c7b986

Browse files
committed
Add static_mut_ref lint
1 parent 1d6f05f commit 7c7b986

File tree

4 files changed

+110
-0
lines changed

4 files changed

+110
-0
lines changed

compiler/rustc_lint/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,10 @@ 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
500+
.label = use of mutable static
501+
.note = use of mutable static is a hard error in 2024 edition
502+
499503
lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target
500504
.label = target type is set here
501505

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

+9
Original file line numberDiff line numberDiff line change
@@ -1845,3 +1845,12 @@ 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+
pub span: Span,
1856+
}
+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
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_span::{def_id::LocalDefId, Span};
12+
use rustc_type_ir::Mutability;
13+
14+
declare_lint! {
15+
/// The `static_mut_ref` lint checks for use of mutable static
16+
/// inside `unsafe` blocks and `unsafe` functions.
17+
///
18+
/// ### Example
19+
///
20+
/// ```rust,no_run,edition2024
21+
/// fn main() {
22+
/// static mut X: i32 = 23;
23+
/// unsafe {
24+
/// let y = &X;
25+
/// }
26+
/// }
27+
///
28+
/// unsafe fn foo() {
29+
/// static mut X: i32 = 23;
30+
/// let y = &X;
31+
/// }
32+
/// ```
33+
///
34+
/// {{produces}}
35+
///
36+
/// ### Explanation
37+
///
38+
/// Use of mutable static is almost always a mistake and can lead to
39+
/// undefined behavior and various other problems in your code.
40+
///
41+
/// This lint is "warm" by default on editions up to 2021, from 2024 it is
42+
/// a hard error.
43+
pub STATIC_MUT_REF,
44+
Warn,
45+
"use of mutable static"
46+
}
47+
48+
declare_lint_pass!(StaticMutRef => [STATIC_MUT_REF]);
49+
50+
impl<'tcx> LateLintPass<'tcx> for StaticMutRef {
51+
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
52+
if let BlockCheckMode::UnsafeBlock(src) = block.rules
53+
&& matches!(src, UserProvided)
54+
{
55+
check_stmts(cx, block.stmts);
56+
}
57+
}
58+
59+
fn check_fn(
60+
&mut self,
61+
cx: &LateContext<'tcx>,
62+
fn_kind: FnKind<'tcx>,
63+
_: &'tcx FnDecl<'tcx>,
64+
body: &'tcx Body<'tcx>,
65+
_: Span,
66+
_: LocalDefId,
67+
) {
68+
if let FnKind::ItemFn(_, _, h) = fn_kind
69+
&& matches!(h.unsafety, Unsafety::Unsafe)
70+
{
71+
if let ExprKind::Block(block, _) = body.value.kind {
72+
check_stmts(cx, block.stmts);
73+
}
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+
cx.emit_spanned_lint(STATIC_MUT_REF, span, UseOfStaticMut { span });
92+
}
93+
}
94+
}

0 commit comments

Comments
 (0)