Skip to content

Commit 5ba6db1

Browse files
committed
Auto merge of rust-lang#124895 - obeis:static-mut-hidden-ref, r=compiler-errors
Disallow hidden references to mutable static Closes rust-lang#123060 Tracking: - rust-lang#123758
2 parents fb46739 + 3b0ce1b commit 5ba6db1

File tree

124 files changed

+1006
-877
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

124 files changed

+1006
-877
lines changed

compiler/rustc_driver_impl/src/signal_handler.rs

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ macro raw_errln($tokens:tt) {
3535
}
3636

3737
/// Signal handler installed for SIGSEGV
38+
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
39+
#[allow(static_mut_refs)]
3840
extern "C" fn print_stack_trace(_: libc::c_int) {
3941
const MAX_FRAMES: usize = 256;
4042
// Reserve data segment so we don't have to malloc in a signal handler, which might fail

compiler/rustc_error_codes/src/error_codes/E0796.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1+
#### Note: this error code is no longer emitted by the compiler.
2+
13
You have created a reference to a mutable static.
24

35
Erroneous code example:
46

5-
```compile_fail,edition2024,E0796
7+
```
68
static mut X: i32 = 23;
7-
89
fn work() {
910
let _val = unsafe { X };
1011
}
11-
1212
let x_ref = unsafe { &mut X };
1313
work();
1414
// The next line has Undefined Behavior!

compiler/rustc_error_codes/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -681,3 +681,4 @@ E0800: 0800,
681681
// E0723, // unstable feature in `const` context
682682
// E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
683683
// E0744, // merged into E0728
684+
// E0796, // unused error code. We use `static_mut_refs` lint instead.

compiler/rustc_hir_analysis/messages.ftl

-19
Original file line numberDiff line numberDiff line change
@@ -467,25 +467,6 @@ hir_analysis_start_not_target_feature = `#[start]` function is not allowed to ha
467467
hir_analysis_start_not_track_caller = `#[start]` function is not allowed to be `#[track_caller]`
468468
.label = `#[start]` function is not allowed to be `#[track_caller]`
469469
470-
hir_analysis_static_mut_ref = creating a {$shared} reference to a mutable static
471-
.label = {$shared} reference to mutable static
472-
.note = {$shared ->
473-
[shared] this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
474-
*[mutable] this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
475-
}
476-
.suggestion = use `addr_of!` instead to create a raw pointer
477-
.suggestion_mut = use `addr_of_mut!` instead to create a raw pointer
478-
479-
hir_analysis_static_mut_refs_lint = creating a {$shared} reference to mutable static is discouraged
480-
.label = {$shared} reference to mutable static
481-
.suggestion = use `addr_of!` instead to create a raw pointer
482-
.suggestion_mut = use `addr_of_mut!` instead to create a raw pointer
483-
.note = this will be a hard error in the 2024 edition
484-
.why_note = {$shared ->
485-
[shared] this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
486-
*[mutable] this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
487-
}
488-
489470
hir_analysis_static_specialize = cannot specialize on `'static` lifetime
490471
491472
hir_analysis_tait_forward_compat = item constrains opaque type that is not in its signature

compiler/rustc_hir_analysis/src/check/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ mod check;
6666
mod compare_impl_item;
6767
pub mod dropck;
6868
mod entry;
69-
mod errs;
7069
pub mod intrinsic;
7170
pub mod intrinsicck;
7271
mod region;

compiler/rustc_hir_analysis/src/check/region.rs

-6
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ use rustc_middle::ty::TyCtxt;
2020
use rustc_span::source_map;
2121
use tracing::debug;
2222

23-
use super::errs::{maybe_expr_static_mut, maybe_stmt_static_mut};
24-
2523
#[derive(Debug, Copy, Clone)]
2624
struct Context {
2725
/// The scope that contains any new variables declared, plus its depth in
@@ -229,8 +227,6 @@ fn resolve_stmt<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, stmt: &'tcx h
229227
let stmt_id = stmt.hir_id.local_id;
230228
debug!("resolve_stmt(stmt.id={:?})", stmt_id);
231229

232-
maybe_stmt_static_mut(visitor.tcx, *stmt);
233-
234230
// Every statement will clean up the temporaries created during
235231
// execution of that statement. Therefore each statement has an
236232
// associated destruction scope that represents the scope of the
@@ -249,8 +245,6 @@ fn resolve_stmt<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, stmt: &'tcx h
249245
fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
250246
debug!("resolve_expr - pre-increment {} expr = {:?}", visitor.expr_and_pat_count, expr);
251247

252-
maybe_expr_static_mut(visitor.tcx, *expr);
253-
254248
let prev_cx = visitor.cx;
255249
visitor.enter_node_scope_with_dtor(expr.hir_id.local_id);
256250

compiler/rustc_hir_analysis/src/errors.rs

-51
Original file line numberDiff line numberDiff line change
@@ -1522,57 +1522,6 @@ pub(crate) struct OnlyCurrentTraitsPointerSugg<'a> {
15221522
pub ptr_ty: Ty<'a>,
15231523
}
15241524

1525-
#[derive(Diagnostic)]
1526-
#[diag(hir_analysis_static_mut_ref, code = E0796)]
1527-
#[note]
1528-
pub(crate) struct StaticMutRef<'a> {
1529-
#[primary_span]
1530-
#[label]
1531-
pub span: Span,
1532-
#[subdiagnostic]
1533-
pub sugg: MutRefSugg,
1534-
pub shared: &'a str,
1535-
}
1536-
1537-
#[derive(Subdiagnostic)]
1538-
pub(crate) enum MutRefSugg {
1539-
#[multipart_suggestion(
1540-
hir_analysis_suggestion,
1541-
style = "verbose",
1542-
applicability = "maybe-incorrect"
1543-
)]
1544-
Shared {
1545-
#[suggestion_part(code = "addr_of!(")]
1546-
lo: Span,
1547-
#[suggestion_part(code = ")")]
1548-
hi: Span,
1549-
},
1550-
#[multipart_suggestion(
1551-
hir_analysis_suggestion_mut,
1552-
style = "verbose",
1553-
applicability = "maybe-incorrect"
1554-
)]
1555-
Mut {
1556-
#[suggestion_part(code = "addr_of_mut!(")]
1557-
lo: Span,
1558-
#[suggestion_part(code = ")")]
1559-
hi: Span,
1560-
},
1561-
}
1562-
1563-
// STATIC_MUT_REF lint
1564-
#[derive(LintDiagnostic)]
1565-
#[diag(hir_analysis_static_mut_refs_lint)]
1566-
#[note]
1567-
#[note(hir_analysis_why_note)]
1568-
pub(crate) struct RefOfMutStatic<'a> {
1569-
#[label]
1570-
pub span: Span,
1571-
#[subdiagnostic]
1572-
pub sugg: MutRefSugg,
1573-
pub shared: &'a str,
1574-
}
1575-
15761525
#[derive(Diagnostic)]
15771526
#[diag(hir_analysis_not_supported_delegation)]
15781527
pub(crate) struct UnsupportedDelegation<'a> {

compiler/rustc_lint/messages.ftl

+7
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,13 @@ lint_single_use_lifetime = lifetime parameter `{$ident}` only used once
769769
770770
lint_span_use_eq_ctxt = use `.eq_ctxt()` instead of `.ctxt() == .ctxt()`
771771
772+
lint_static_mut_refs_lint = creating a {$shared_label}reference to mutable static is discouraged
773+
.label = {$shared_label}reference to mutable static
774+
.suggestion = use `&raw const` instead to create a raw pointer
775+
.suggestion_mut = use `&raw mut` instead to create a raw pointer
776+
.shared_note = shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
777+
.mut_note = mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives
778+
772779
lint_supertrait_as_deref_target = this `Deref` implementation is covered by an implicit supertrait coercion
773780
.label = `{$self_ty}` implements `Deref<Target = dyn {$target_principal}>` which conflicts with supertrait `{$supertrait_principal}`
774781
.label2 = target type is a supertrait of `{$self_ty}`

compiler/rustc_lint/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ mod ptr_nulls;
8181
mod redundant_semicolon;
8282
mod reference_casting;
8383
mod shadowed_into_iter;
84+
mod static_mut_refs;
8485
mod tail_expr_drop_order;
8586
mod traits;
8687
mod types;
@@ -120,6 +121,7 @@ use rustc_middle::query::Providers;
120121
use rustc_middle::ty::TyCtxt;
121122
use shadowed_into_iter::ShadowedIntoIter;
122123
pub use shadowed_into_iter::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
124+
use static_mut_refs::*;
123125
use tail_expr_drop_order::TailExprDropOrder;
124126
use traits::*;
125127
use types::*;
@@ -246,6 +248,7 @@ late_lint_methods!(
246248
ImplTraitOvercaptures: ImplTraitOvercaptures,
247249
TailExprDropOrder: TailExprDropOrder,
248250
IfLetRescope: IfLetRescope::default(),
251+
StaticMutRefs: StaticMutRefs,
249252
]
250253
]
251254
);

compiler/rustc_lint/src/lints.rs

+32
Original file line numberDiff line numberDiff line change
@@ -3061,3 +3061,35 @@ pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion {
30613061
pub(crate) struct OutOfScopeMacroCalls {
30623062
pub path: String,
30633063
}
3064+
3065+
#[derive(LintDiagnostic)]
3066+
#[diag(lint_static_mut_refs_lint)]
3067+
pub(crate) struct RefOfMutStatic<'a> {
3068+
#[label]
3069+
pub span: Span,
3070+
#[subdiagnostic]
3071+
pub sugg: Option<MutRefSugg>,
3072+
pub shared_label: &'a str,
3073+
#[note(lint_shared_note)]
3074+
pub shared_note: bool,
3075+
#[note(lint_mut_note)]
3076+
pub mut_note: bool,
3077+
}
3078+
3079+
#[derive(Subdiagnostic)]
3080+
pub(crate) enum MutRefSugg {
3081+
#[multipart_suggestion(lint_suggestion, style = "verbose", applicability = "maybe-incorrect")]
3082+
Shared {
3083+
#[suggestion_part(code = "&raw const ")]
3084+
span: Span,
3085+
},
3086+
#[multipart_suggestion(
3087+
lint_suggestion_mut,
3088+
style = "verbose",
3089+
applicability = "maybe-incorrect"
3090+
)]
3091+
Mut {
3092+
#[suggestion_part(code = "&raw mut ")]
3093+
span: Span,
3094+
},
3095+
}
+154
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
use rustc_hir as hir;
2+
use rustc_hir::{Expr, Stmt};
3+
use rustc_middle::ty::{Mutability, TyKind};
4+
use rustc_session::lint::FutureIncompatibilityReason;
5+
use rustc_session::{declare_lint, declare_lint_pass};
6+
use rustc_span::edition::Edition;
7+
use rustc_span::Span;
8+
9+
use crate::lints::{MutRefSugg, RefOfMutStatic};
10+
use crate::{LateContext, LateLintPass, LintContext};
11+
12+
declare_lint! {
13+
/// The `static_mut_refs` lint checks for shared or mutable references
14+
/// of mutable static inside `unsafe` blocks and `unsafe` functions.
15+
///
16+
/// ### Example
17+
///
18+
/// ```rust,edition2021
19+
/// fn main() {
20+
/// static mut X: i32 = 23;
21+
/// static mut Y: i32 = 24;
22+
///
23+
/// unsafe {
24+
/// let y = &X;
25+
/// let ref x = X;
26+
/// let (x, y) = (&X, &Y);
27+
/// foo(&X);
28+
/// }
29+
/// }
30+
///
31+
/// unsafe fn _foo() {
32+
/// static mut X: i32 = 23;
33+
/// static mut Y: i32 = 24;
34+
///
35+
/// let y = &X;
36+
/// let ref x = X;
37+
/// let (x, y) = (&X, &Y);
38+
/// foo(&X);
39+
/// }
40+
///
41+
/// fn foo<'a>(_x: &'a i32) {}
42+
/// ```
43+
///
44+
/// {{produces}}
45+
///
46+
/// ### Explanation
47+
///
48+
/// Shared or mutable references of mutable static are almost always a mistake and
49+
/// can lead to undefined behavior and various other problems in your code.
50+
///
51+
/// This lint is "warn" by default on editions up to 2021, in 2024 is "deny".
52+
pub STATIC_MUT_REFS,
53+
Warn,
54+
"shared references or mutable references of mutable static is discouraged",
55+
@future_incompatible = FutureIncompatibleInfo {
56+
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
57+
reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>",
58+
explain_reason: false,
59+
};
60+
@edition Edition2024 => Deny;
61+
}
62+
63+
declare_lint_pass!(StaticMutRefs => [STATIC_MUT_REFS]);
64+
65+
impl<'tcx> LateLintPass<'tcx> for StaticMutRefs {
66+
#[allow(rustc::usage_of_ty_tykind)]
67+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
68+
let err_span = expr.span;
69+
match expr.kind {
70+
hir::ExprKind::AddrOf(borrow_kind, m, ex)
71+
if matches!(borrow_kind, hir::BorrowKind::Ref)
72+
&& let Some(err_span) = path_is_static_mut(ex, err_span) =>
73+
{
74+
emit_static_mut_refs(
75+
cx,
76+
err_span,
77+
err_span.with_hi(ex.span.lo()),
78+
m,
79+
!expr.span.from_expansion(),
80+
);
81+
}
82+
hir::ExprKind::MethodCall(_, e, _, _)
83+
if let Some(err_span) = path_is_static_mut(e, expr.span)
84+
&& let typeck = cx.typeck_results()
85+
&& let Some(method_def_id) = typeck.type_dependent_def_id(expr.hir_id)
86+
&& let inputs =
87+
cx.tcx.fn_sig(method_def_id).skip_binder().inputs().skip_binder()
88+
&& let Some(receiver) = inputs.get(0)
89+
&& let TyKind::Ref(_, _, m) = receiver.kind() =>
90+
{
91+
emit_static_mut_refs(cx, err_span, err_span.shrink_to_lo(), *m, false);
92+
}
93+
_ => {}
94+
}
95+
}
96+
97+
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'_>) {
98+
if let hir::StmtKind::Let(loc) = stmt.kind
99+
&& let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind
100+
&& let hir::ByRef::Yes(m) = ba.0
101+
&& let Some(init) = loc.init
102+
&& let Some(err_span) = path_is_static_mut(init, init.span)
103+
{
104+
emit_static_mut_refs(cx, err_span, err_span.shrink_to_lo(), m, false);
105+
}
106+
}
107+
}
108+
109+
fn path_is_static_mut(mut expr: &hir::Expr<'_>, mut err_span: Span) -> Option<Span> {
110+
if err_span.from_expansion() {
111+
err_span = expr.span;
112+
}
113+
114+
while let hir::ExprKind::Field(e, _) = expr.kind {
115+
expr = e;
116+
}
117+
118+
if let hir::ExprKind::Path(qpath) = expr.kind
119+
&& let hir::QPath::Resolved(_, path) = qpath
120+
&& let hir::def::Res::Def(def_kind, _) = path.res
121+
&& let hir::def::DefKind::Static { safety: _, mutability: Mutability::Mut, nested: false } =
122+
def_kind
123+
{
124+
return Some(err_span);
125+
}
126+
None
127+
}
128+
129+
fn emit_static_mut_refs(
130+
cx: &LateContext<'_>,
131+
span: Span,
132+
sugg_span: Span,
133+
mutable: Mutability,
134+
suggest_addr_of: bool,
135+
) {
136+
let (shared_label, shared_note, mut_note, sugg) = match mutable {
137+
Mutability::Mut => {
138+
let sugg =
139+
if suggest_addr_of { Some(MutRefSugg::Mut { span: sugg_span }) } else { None };
140+
("mutable ", false, true, sugg)
141+
}
142+
Mutability::Not => {
143+
let sugg =
144+
if suggest_addr_of { Some(MutRefSugg::Shared { span: sugg_span }) } else { None };
145+
("shared ", true, false, sugg)
146+
}
147+
};
148+
149+
cx.emit_span_lint(
150+
STATIC_MUT_REFS,
151+
span,
152+
RefOfMutStatic { span, sugg, shared_label, shared_note, mut_note },
153+
);
154+
}

0 commit comments

Comments
 (0)