Disallow reference to static mut
for expressions
Add `E0796` error code. Add `static_mut_ref` lint. This is the idea for the 2024 edition.
This commit is contained in:
parent
595bc6f003
commit
2c088f9520
@ -3877,6 +3877,7 @@ dependencies = [
|
|||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
"rustc_fluent_macro",
|
"rustc_fluent_macro",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
|
"rustc_hir_pretty",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_infer",
|
"rustc_infer",
|
||||||
"rustc_lint_defs",
|
"rustc_lint_defs",
|
||||||
|
@ -515,6 +515,7 @@
|
|||||||
E0793: include_str!("./error_codes/E0793.md"),
|
E0793: include_str!("./error_codes/E0793.md"),
|
||||||
E0794: include_str!("./error_codes/E0794.md"),
|
E0794: include_str!("./error_codes/E0794.md"),
|
||||||
E0795: include_str!("./error_codes/E0795.md"),
|
E0795: include_str!("./error_codes/E0795.md"),
|
||||||
|
E0796: include_str!("./error_codes/E0796.md"),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Undocumented removed error codes. Note that many removed error codes are kept in the list above
|
// Undocumented removed error codes. Note that many removed error codes are kept in the list above
|
||||||
|
22
compiler/rustc_error_codes/src/error_codes/E0796.md
Normal file
22
compiler/rustc_error_codes/src/error_codes/E0796.md
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
Reference of mutable static.
|
||||||
|
|
||||||
|
Erroneous code example:
|
||||||
|
|
||||||
|
```compile_fail,edition2024,E0796
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo<'a>(_x: &'a i32) {}
|
||||||
|
```
|
||||||
|
|
||||||
|
Mutable statics can be written to by multiple threads: aliasing violations or
|
||||||
|
data races will cause undefined behavior.
|
||||||
|
|
||||||
|
Reference of mutable static is a hard error from 2024 edition.
|
@ -17,6 +17,7 @@ rustc_errors = { path = "../rustc_errors" }
|
|||||||
rustc_feature = { path = "../rustc_feature" }
|
rustc_feature = { path = "../rustc_feature" }
|
||||||
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||||
rustc_hir = { path = "../rustc_hir" }
|
rustc_hir = { path = "../rustc_hir" }
|
||||||
|
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
|
||||||
rustc_index = { path = "../rustc_index" }
|
rustc_index = { path = "../rustc_index" }
|
||||||
rustc_infer = { path = "../rustc_infer" }
|
rustc_infer = { path = "../rustc_infer" }
|
||||||
rustc_lint_defs = { path = "../rustc_lint_defs" }
|
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]`
|
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]`
|
.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_static_specialize = cannot specialize on `'static` lifetime
|
||||||
|
|
||||||
hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl
|
hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl
|
||||||
|
78
compiler/rustc_hir_analysis/src/check/errs.rs
Normal file
78
compiler/rustc_hir_analysis/src/check/errs.rs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 compare_impl_item;
|
mod compare_impl_item;
|
||||||
pub mod dropck;
|
pub mod dropck;
|
||||||
mod entry;
|
mod entry;
|
||||||
|
mod errs;
|
||||||
pub mod intrinsic;
|
pub mod intrinsic;
|
||||||
pub mod intrinsicck;
|
pub mod intrinsicck;
|
||||||
mod region;
|
mod region;
|
||||||
|
@ -1410,3 +1410,94 @@ pub struct OnlyCurrentTraitsPointerSugg<'a> {
|
|||||||
pub mut_key: &'a str,
|
pub mut_key: &'a str,
|
||||||
pub ptr_ty: Ty<'a>,
|
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,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
@ -89,6 +89,7 @@
|
|||||||
SINGLE_USE_LIFETIMES,
|
SINGLE_USE_LIFETIMES,
|
||||||
SOFT_UNSTABLE,
|
SOFT_UNSTABLE,
|
||||||
STABLE_FEATURES,
|
STABLE_FEATURES,
|
||||||
|
STATIC_MUT_REF,
|
||||||
SUSPICIOUS_AUTO_TRAIT_IMPLS,
|
SUSPICIOUS_AUTO_TRAIT_IMPLS,
|
||||||
TEST_UNSTABLE_LINT,
|
TEST_UNSTABLE_LINT,
|
||||||
TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
|
TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
|
||||||
@ -1767,6 +1768,57 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `static_mut_ref` 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, from 2024 there is
|
||||||
|
/// a hard error instead.
|
||||||
|
pub STATIC_MUT_REF,
|
||||||
|
Warn,
|
||||||
|
"shared references or mutable references of mutable static is discouraged",
|
||||||
|
@future_incompatible = FutureIncompatibleInfo {
|
||||||
|
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
|
||||||
|
reference: "issue #114447 <https://github.com/rust-lang/rust/issues/114447>",
|
||||||
|
explain_reason: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
/// The `absolute_paths_not_starting_with_crate` lint detects fully
|
/// The `absolute_paths_not_starting_with_crate` lint detects fully
|
||||||
/// qualified paths that start with a module name instead of `crate`,
|
/// qualified paths that start with a module name instead of `crate`,
|
||||||
|
Loading…
Reference in New Issue
Block a user