Skip to content

Commit

Permalink
Add static_mut_ref lint
Browse files Browse the repository at this point in the history
  • Loading branch information
obeis committed Nov 10, 2023
1 parent 1d6f05f commit b76da64
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 0 deletions.
6 changes: 6 additions & 0 deletions compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,12 @@ lint_requested_level = requested on the command line with `{$level} {$lint_name}
lint_span_use_eq_ctxt = use `.eq_ctxt()` instead of `.ctxt() == .ctxt()`
lint_static_mut_ref = use of mutable static is discouraged
.label = use of mutable static
.note = use of mutable static is a hard error from 2024 edition
lint_static_mut_ref_why_note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target
.label = target type is set here
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ mod passes;
mod ptr_nulls;
mod redundant_semicolon;
mod reference_casting;
mod static_mut_ref;
mod traits;
mod types;
mod unused;
Expand Down Expand Up @@ -121,6 +122,7 @@ use pass_by_value::*;
use ptr_nulls::*;
use redundant_semicolon::*;
use reference_casting::*;
use static_mut_ref::*;
use traits::*;
use types::*;
use unused::*;
Expand Down Expand Up @@ -239,6 +241,7 @@ late_lint_methods!(
MissingDebugImplementations: MissingDebugImplementations,
MissingDoc: MissingDoc,
AsyncFnInTrait: AsyncFnInTrait,
StaticMutRef: StaticMutRef,
]
]
);
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1845,3 +1845,14 @@ impl<'a> DecorateLint<'a, ()> for AsyncFnInTraitDiag {
fluent::lint_async_fn_in_trait
}
}

// static_mut_ref.rs
#[derive(LintDiagnostic)]
#[diag(lint_static_mut_ref)]
#[note]
pub struct UseOfStaticMut {
#[label]
pub span: Span,
#[note(lint_static_mut_ref_why_note)]
pub why_note: (),
}
93 changes: 93 additions & 0 deletions compiler/rustc_lint/src/static_mut_ref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use crate::lints::UseOfStaticMut;
use crate::{LateContext, LateLintPass, LintContext};
use rustc_ast::BorrowKind;
use rustc_hir::{
def::{DefKind, Res::Def},
intravisit::FnKind,
Block, BlockCheckMode, Body, ExprKind, FnDecl, QPath, Stmt, StmtKind,
UnsafeSource::UserProvided,
Unsafety,
};
use rustc_span::{def_id::LocalDefId, Span};
use rustc_type_ir::Mutability;

declare_lint! {
/// The `static_mut_ref` lint checks for use of mutable static
/// inside `unsafe` blocks and `unsafe` functions.
///
/// ### Example
///
/// ```rust,no_run,edition2024
/// fn main() {
/// static mut X: i32 = 23;
/// unsafe {
/// let y = &X;
/// }
/// }
///
/// unsafe fn foo() {
/// static mut X: i32 = 23;
/// let y = &X;
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Use of mutable static is almost always a mistake and can lead to
/// undefined behavior and various other problems in your code.
///
/// This lint is "warn" by default on editions up to 2021, from 2024 it is
/// a hard error.
pub STATIC_MUT_REF,
Warn,
"use of mutable static is discouraged"
}

declare_lint_pass!(StaticMutRef => [STATIC_MUT_REF]);

impl<'tcx> LateLintPass<'tcx> for StaticMutRef {
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
if let BlockCheckMode::UnsafeBlock(src) = block.rules
&& matches!(src, UserProvided)
{
check_stmts(cx, block.stmts);
}
}

fn check_fn(
&mut self,
cx: &LateContext<'tcx>,
fn_kind: FnKind<'tcx>,
_: &'tcx FnDecl<'tcx>,
body: &'tcx Body<'tcx>,
_: Span,
_: LocalDefId,
) {
if let FnKind::ItemFn(_, _, h) = fn_kind
&& matches!(h.unsafety, Unsafety::Unsafe)
&& let ExprKind::Block(block, _) = body.value.kind
{
check_stmts(cx, block.stmts);
}
}
}

fn check_stmts(cx: &LateContext<'_>, stmts: &[Stmt<'_>]) {
for stmt in stmts.iter() {
if let StmtKind::Local(loc) = stmt.kind
&& let Some(init) = loc.init
&& let ExprKind::AddrOf(borrow_kind, _, expr) = init.kind
&& matches!(borrow_kind, BorrowKind::Ref)
&& let ExprKind::Path(qpath) = expr.kind
&& let QPath::Resolved(_, path) = qpath
&& let Def(def_kind, _) = path.res
&& let DefKind::Static(mt) = def_kind
&& matches!(mt, Mutability::Mut)
{
let span = init.span;
cx.emit_spanned_lint(STATIC_MUT_REF, span, UseOfStaticMut { span, why_note: () });
}
}
}

0 comments on commit b76da64

Please sign in to comment.