Auto merge of #124895 - obeis:static-mut-hidden-ref, r=compiler-errors
Disallow hidden references to mutable static Closes #123060 Tracking: - https://github.com/rust-lang/rust/issues/123758
This commit is contained in:
commit
5ba6db1b64
124 changed files with 1006 additions and 877 deletions
|
@ -81,6 +81,7 @@ mod ptr_nulls;
|
|||
mod redundant_semicolon;
|
||||
mod reference_casting;
|
||||
mod shadowed_into_iter;
|
||||
mod static_mut_refs;
|
||||
mod tail_expr_drop_order;
|
||||
mod traits;
|
||||
mod types;
|
||||
|
@ -120,6 +121,7 @@ use rustc_middle::query::Providers;
|
|||
use rustc_middle::ty::TyCtxt;
|
||||
use shadowed_into_iter::ShadowedIntoIter;
|
||||
pub use shadowed_into_iter::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
|
||||
use static_mut_refs::*;
|
||||
use tail_expr_drop_order::TailExprDropOrder;
|
||||
use traits::*;
|
||||
use types::*;
|
||||
|
@ -246,6 +248,7 @@ late_lint_methods!(
|
|||
ImplTraitOvercaptures: ImplTraitOvercaptures,
|
||||
TailExprDropOrder: TailExprDropOrder,
|
||||
IfLetRescope: IfLetRescope::default(),
|
||||
StaticMutRefs: StaticMutRefs,
|
||||
]
|
||||
]
|
||||
);
|
||||
|
|
|
@ -3061,3 +3061,35 @@ pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion {
|
|||
pub(crate) struct OutOfScopeMacroCalls {
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_static_mut_refs_lint)]
|
||||
pub(crate) struct RefOfMutStatic<'a> {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sugg: Option<MutRefSugg>,
|
||||
pub shared_label: &'a str,
|
||||
#[note(lint_shared_note)]
|
||||
pub shared_note: bool,
|
||||
#[note(lint_mut_note)]
|
||||
pub mut_note: bool,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum MutRefSugg {
|
||||
#[multipart_suggestion(lint_suggestion, style = "verbose", applicability = "maybe-incorrect")]
|
||||
Shared {
|
||||
#[suggestion_part(code = "&raw const ")]
|
||||
span: Span,
|
||||
},
|
||||
#[multipart_suggestion(
|
||||
lint_suggestion_mut,
|
||||
style = "verbose",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
Mut {
|
||||
#[suggestion_part(code = "&raw mut ")]
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
|
154
compiler/rustc_lint/src/static_mut_refs.rs
Normal file
154
compiler/rustc_lint/src/static_mut_refs.rs
Normal file
|
@ -0,0 +1,154 @@
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::{Expr, Stmt};
|
||||
use rustc_middle::ty::{Mutability, TyKind};
|
||||
use rustc_session::lint::FutureIncompatibilityReason;
|
||||
use rustc_session::{declare_lint, declare_lint_pass};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::lints::{MutRefSugg, RefOfMutStatic};
|
||||
use crate::{LateContext, LateLintPass, LintContext};
|
||||
|
||||
declare_lint! {
|
||||
/// The `static_mut_refs` lint checks for shared or mutable references
|
||||
/// of mutable static inside `unsafe` blocks and `unsafe` functions.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,edition2021
|
||||
/// fn main() {
|
||||
/// static mut X: i32 = 23;
|
||||
/// static mut Y: i32 = 24;
|
||||
///
|
||||
/// unsafe {
|
||||
/// let y = &X;
|
||||
/// let ref x = X;
|
||||
/// let (x, y) = (&X, &Y);
|
||||
/// foo(&X);
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// unsafe fn _foo() {
|
||||
/// static mut X: i32 = 23;
|
||||
/// static mut Y: i32 = 24;
|
||||
///
|
||||
/// let y = &X;
|
||||
/// let ref x = X;
|
||||
/// let (x, y) = (&X, &Y);
|
||||
/// foo(&X);
|
||||
/// }
|
||||
///
|
||||
/// fn foo<'a>(_x: &'a i32) {}
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Shared or mutable references of mutable static are 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, in 2024 is "deny".
|
||||
pub STATIC_MUT_REFS,
|
||||
Warn,
|
||||
"shared references or mutable references of mutable static is discouraged",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
|
||||
reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>",
|
||||
explain_reason: false,
|
||||
};
|
||||
@edition Edition2024 => Deny;
|
||||
}
|
||||
|
||||
declare_lint_pass!(StaticMutRefs => [STATIC_MUT_REFS]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for StaticMutRefs {
|
||||
#[allow(rustc::usage_of_ty_tykind)]
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
|
||||
let err_span = expr.span;
|
||||
match expr.kind {
|
||||
hir::ExprKind::AddrOf(borrow_kind, m, ex)
|
||||
if matches!(borrow_kind, hir::BorrowKind::Ref)
|
||||
&& let Some(err_span) = path_is_static_mut(ex, err_span) =>
|
||||
{
|
||||
emit_static_mut_refs(
|
||||
cx,
|
||||
err_span,
|
||||
err_span.with_hi(ex.span.lo()),
|
||||
m,
|
||||
!expr.span.from_expansion(),
|
||||
);
|
||||
}
|
||||
hir::ExprKind::MethodCall(_, e, _, _)
|
||||
if let Some(err_span) = path_is_static_mut(e, expr.span)
|
||||
&& let typeck = cx.typeck_results()
|
||||
&& let Some(method_def_id) = typeck.type_dependent_def_id(expr.hir_id)
|
||||
&& let inputs =
|
||||
cx.tcx.fn_sig(method_def_id).skip_binder().inputs().skip_binder()
|
||||
&& let Some(receiver) = inputs.get(0)
|
||||
&& let TyKind::Ref(_, _, m) = receiver.kind() =>
|
||||
{
|
||||
emit_static_mut_refs(cx, err_span, err_span.shrink_to_lo(), *m, false);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'_>) {
|
||||
if let hir::StmtKind::Let(loc) = stmt.kind
|
||||
&& let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind
|
||||
&& let hir::ByRef::Yes(m) = ba.0
|
||||
&& let Some(init) = loc.init
|
||||
&& let Some(err_span) = path_is_static_mut(init, init.span)
|
||||
{
|
||||
emit_static_mut_refs(cx, err_span, err_span.shrink_to_lo(), m, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn path_is_static_mut(mut expr: &hir::Expr<'_>, mut err_span: Span) -> Option<Span> {
|
||||
if err_span.from_expansion() {
|
||||
err_span = expr.span;
|
||||
}
|
||||
|
||||
while let hir::ExprKind::Field(e, _) = expr.kind {
|
||||
expr = e;
|
||||
}
|
||||
|
||||
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 { safety: _, mutability: Mutability::Mut, nested: false } =
|
||||
def_kind
|
||||
{
|
||||
return Some(err_span);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn emit_static_mut_refs(
|
||||
cx: &LateContext<'_>,
|
||||
span: Span,
|
||||
sugg_span: Span,
|
||||
mutable: Mutability,
|
||||
suggest_addr_of: bool,
|
||||
) {
|
||||
let (shared_label, shared_note, mut_note, sugg) = match mutable {
|
||||
Mutability::Mut => {
|
||||
let sugg =
|
||||
if suggest_addr_of { Some(MutRefSugg::Mut { span: sugg_span }) } else { None };
|
||||
("mutable ", false, true, sugg)
|
||||
}
|
||||
Mutability::Not => {
|
||||
let sugg =
|
||||
if suggest_addr_of { Some(MutRefSugg::Shared { span: sugg_span }) } else { None };
|
||||
("shared ", true, false, sugg)
|
||||
}
|
||||
};
|
||||
|
||||
cx.emit_span_lint(
|
||||
STATIC_MUT_REFS,
|
||||
span,
|
||||
RefOfMutStatic { span, sugg, shared_label, shared_note, mut_note },
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue