Rollup merge of #117556 - obeis:static-mut-ref-lint, r=davidtwco
Disallow reference to `static mut` and adding `static_mut_ref` lint Closes #114447 r? `@scottmcm`
This commit is contained in:
commit
4a24b5bc05
71 changed files with 1447 additions and 237 deletions
|
@ -17,6 +17,7 @@ rustc_errors = { path = "../rustc_errors" }
|
|||
rustc_feature = { path = "../rustc_feature" }
|
||||
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_infer = { path = "../rustc_infer" }
|
||||
rustc_lint_defs = { path = "../rustc_lint_defs" }
|
||||
|
|
|
@ -346,6 +346,20 @@ hir_analysis_start_not_target_feature = `#[start]` function is not allowed to ha
|
|||
hir_analysis_start_not_track_caller = `#[start]` function is not allowed to be `#[track_caller]`
|
||||
.label = `#[start]` function is not allowed to be `#[track_caller]`
|
||||
|
||||
hir_analysis_static_mut_ref = reference of mutable static is disallowed
|
||||
.label = reference of mutable static
|
||||
.note = mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
|
||||
.suggestion = shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
|
||||
.suggestion_mut = mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
|
||||
|
||||
hir_analysis_static_mut_ref_lint = {$shared}reference of mutable static is discouraged
|
||||
.label = shared reference of mutable static
|
||||
.label_mut = mutable reference of mutable static
|
||||
.suggestion = shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
|
||||
.suggestion_mut = mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
|
||||
.note = reference of mutable static is a hard error from 2024 edition
|
||||
.why_note = mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
|
||||
|
||||
hir_analysis_static_specialize = cannot specialize on `'static` lifetime
|
||||
|
||||
hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl
|
||||
|
|
97
compiler/rustc_hir_analysis/src/check/errs.rs
Normal file
97
compiler/rustc_hir_analysis/src/check/errs.rs
Normal file
|
@ -0,0 +1,97 @@
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir_pretty::qpath_to_string;
|
||||
use rustc_lint_defs::builtin::STATIC_MUT_REF;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::Span;
|
||||
use rustc_type_ir::Mutability;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
/// Check for shared or mutable references of `static mut` inside expression
|
||||
pub fn maybe_expr_static_mut(tcx: TyCtxt<'_>, expr: hir::Expr<'_>) {
|
||||
let span = expr.span;
|
||||
let hir_id = expr.hir_id;
|
||||
if let hir::ExprKind::AddrOf(borrow_kind, m, expr) = expr.kind
|
||||
&& matches!(borrow_kind, hir::BorrowKind::Ref)
|
||||
&& let Some(var) = is_path_static_mut(*expr)
|
||||
{
|
||||
handle_static_mut_ref(
|
||||
tcx,
|
||||
span,
|
||||
var,
|
||||
span.edition().at_least_rust_2024(),
|
||||
matches!(m, Mutability::Mut),
|
||||
hir_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Check for shared or mutable references of `static mut` inside statement
|
||||
pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) {
|
||||
if let hir::StmtKind::Local(loc) = stmt.kind
|
||||
&& let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind
|
||||
&& matches!(ba.0, rustc_ast::ByRef::Yes)
|
||||
&& let Some(init) = loc.init
|
||||
&& let Some(var) = is_path_static_mut(*init)
|
||||
{
|
||||
handle_static_mut_ref(
|
||||
tcx,
|
||||
init.span,
|
||||
var,
|
||||
loc.span.edition().at_least_rust_2024(),
|
||||
matches!(ba.1, Mutability::Mut),
|
||||
stmt.hir_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_path_static_mut(expr: hir::Expr<'_>) -> Option<String> {
|
||||
if let hir::ExprKind::Path(qpath) = expr.kind
|
||||
&& let hir::QPath::Resolved(_, path) = qpath
|
||||
&& let hir::def::Res::Def(def_kind, _) = path.res
|
||||
&& let hir::def::DefKind::Static(mt) = def_kind
|
||||
&& matches!(mt, Mutability::Mut)
|
||||
{
|
||||
return Some(qpath_to_string(&qpath));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn handle_static_mut_ref(
|
||||
tcx: TyCtxt<'_>,
|
||||
span: Span,
|
||||
var: String,
|
||||
e2024: bool,
|
||||
mutable: bool,
|
||||
hir_id: hir::HirId,
|
||||
) {
|
||||
if e2024 {
|
||||
let sugg = if mutable {
|
||||
errors::StaticMutRefSugg::Mut { span, var }
|
||||
} else {
|
||||
errors::StaticMutRefSugg::Shared { span, var }
|
||||
};
|
||||
tcx.sess.parse_sess.dcx.emit_err(errors::StaticMutRef { span, sugg });
|
||||
return;
|
||||
}
|
||||
|
||||
let (label, sugg, shared) = if mutable {
|
||||
(
|
||||
errors::RefOfMutStaticLabel::Mut { span },
|
||||
errors::RefOfMutStaticSugg::Mut { span, var },
|
||||
"mutable ",
|
||||
)
|
||||
} else {
|
||||
(
|
||||
errors::RefOfMutStaticLabel::Shared { span },
|
||||
errors::RefOfMutStaticSugg::Shared { span, var },
|
||||
"shared ",
|
||||
)
|
||||
};
|
||||
tcx.emit_spanned_lint(
|
||||
STATIC_MUT_REF,
|
||||
hir_id,
|
||||
span,
|
||||
errors::RefOfMutStatic { shared, why_note: (), label, sugg },
|
||||
);
|
||||
}
|
|
@ -66,6 +66,7 @@ mod check;
|
|||
mod compare_impl_item;
|
||||
pub mod dropck;
|
||||
mod entry;
|
||||
mod errs;
|
||||
pub mod intrinsic;
|
||||
pub mod intrinsicck;
|
||||
mod region;
|
||||
|
|
|
@ -18,6 +18,8 @@ use rustc_middle::ty::TyCtxt;
|
|||
use rustc_span::source_map;
|
||||
use rustc_span::Span;
|
||||
|
||||
use super::errs::{maybe_expr_static_mut, maybe_stmt_static_mut};
|
||||
|
||||
use std::mem;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
|
@ -224,6 +226,8 @@ fn resolve_stmt<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, stmt: &'tcx h
|
|||
let stmt_id = stmt.hir_id.local_id;
|
||||
debug!("resolve_stmt(stmt.id={:?})", stmt_id);
|
||||
|
||||
maybe_stmt_static_mut(visitor.tcx, *stmt);
|
||||
|
||||
// Every statement will clean up the temporaries created during
|
||||
// execution of that statement. Therefore each statement has an
|
||||
// associated destruction scope that represents the scope of the
|
||||
|
@ -242,6 +246,8 @@ fn resolve_stmt<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, stmt: &'tcx h
|
|||
fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
|
||||
debug!("resolve_expr - pre-increment {} expr = {:?}", visitor.expr_and_pat_count, expr);
|
||||
|
||||
maybe_expr_static_mut(visitor.tcx, *expr);
|
||||
|
||||
let prev_cx = visitor.cx;
|
||||
visitor.enter_node_scope_with_dtor(expr.hir_id.local_id);
|
||||
|
||||
|
|
|
@ -1410,3 +1410,94 @@ pub struct OnlyCurrentTraitsPointerSugg<'a> {
|
|||
pub mut_key: &'a str,
|
||||
pub ptr_ty: Ty<'a>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_static_mut_ref, code = "E0796")]
|
||||
#[note]
|
||||
pub struct StaticMutRef {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sugg: StaticMutRefSugg,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum StaticMutRefSugg {
|
||||
#[suggestion(
|
||||
hir_analysis_suggestion,
|
||||
style = "verbose",
|
||||
code = "addr_of!({var})",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
Shared {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
var: String,
|
||||
},
|
||||
#[suggestion(
|
||||
hir_analysis_suggestion_mut,
|
||||
style = "verbose",
|
||||
code = "addr_of_mut!({var})",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
Mut {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
var: String,
|
||||
},
|
||||
}
|
||||
|
||||
// STATIC_MUT_REF lint
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(hir_analysis_static_mut_ref_lint)]
|
||||
#[note]
|
||||
pub struct RefOfMutStatic<'a> {
|
||||
pub shared: &'a str,
|
||||
#[note(hir_analysis_why_note)]
|
||||
pub why_note: (),
|
||||
#[subdiagnostic]
|
||||
pub label: RefOfMutStaticLabel,
|
||||
#[subdiagnostic]
|
||||
pub sugg: RefOfMutStaticSugg,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum RefOfMutStaticLabel {
|
||||
#[label(hir_analysis_label)]
|
||||
Shared {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[label(hir_analysis_label_mut)]
|
||||
Mut {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum RefOfMutStaticSugg {
|
||||
#[suggestion(
|
||||
hir_analysis_suggestion,
|
||||
style = "verbose",
|
||||
code = "addr_of!({var})",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
Shared {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
var: String,
|
||||
},
|
||||
#[suggestion(
|
||||
hir_analysis_suggestion_mut,
|
||||
style = "verbose",
|
||||
code = "addr_of_mut!({var})",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
Mut {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
var: String,
|
||||
},
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue