Skip to content

Commit b803948

Browse files
committed
Disallow use of static mut inside unsafe block
```rust static mut X: i32 = 23; unsafe { let y = &X; } ``` This is the idea for the 2024 edition. Add `E0796` error code.
1 parent d3dee47 commit b803948

File tree

7 files changed

+75
-1
lines changed

7 files changed

+75
-1
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3936,6 +3936,7 @@ dependencies = [
39363936
"rustc_feature",
39373937
"rustc_fluent_macro",
39383938
"rustc_hir",
3939+
"rustc_hir_pretty",
39393940
"rustc_index",
39403941
"rustc_infer",
39413942
"rustc_lint_defs",

compiler/rustc_error_codes/src/error_codes.rs

+1
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,7 @@ E0792: include_str!("./error_codes/E0792.md"),
515515
E0793: include_str!("./error_codes/E0793.md"),
516516
E0794: include_str!("./error_codes/E0794.md"),
517517
E0795: include_str!("./error_codes/E0795.md"),
518+
E0796: include_str!("./error_codes/E0796.md"),
518519
}
519520

520521
// Undocumented removed error codes. Note that many removed error codes are kept in the list above
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Use of mutable static.
2+
3+
Erroneous code example:
4+
5+
```compile_fail,edition2024,E0796
6+
static mut X: i32 = 23;
7+
unsafe {
8+
let y = &X;
9+
}
10+
11+
unsafe fn foo() {
12+
static mut X: i32 = 1;
13+
let y = &X;
14+
}
15+
```
16+
17+
Mutable statics can be written to by multiple threads: aliasing violations or
18+
data races will cause undefined behavior.
19+
20+
Use of mutable static is a hard error from 2024 edition.

compiler/rustc_hir_analysis/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ rustc_errors = { path = "../rustc_errors" }
1717
rustc_feature = { path = "../rustc_feature" }
1818
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
1919
rustc_hir = { path = "../rustc_hir" }
20+
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
2021
rustc_index = { path = "../rustc_index" }
2122
rustc_infer = { path = "../rustc_infer" }
2223
rustc_lint_defs = { path = "../rustc_lint_defs" }

compiler/rustc_hir_analysis/messages.ftl

+5
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,11 @@ hir_analysis_start_not_target_feature = `#[start]` function is not allowed to ha
333333
hir_analysis_start_not_track_caller = `#[start]` function is not allowed to be `#[track_caller]`
334334
.label = `#[start]` function is not allowed to be `#[track_caller]`
335335
336+
hir_analysis_static_mut_ref = use of mutable static is disallowed
337+
.label = use of mutable static
338+
.note = mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
339+
.suggestion = use `addr_of_mut!` macro
340+
336341
hir_analysis_static_specialize = cannot specialize on `'static` lifetime
337342
338343
hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl

compiler/rustc_hir_analysis/src/check/region.rs

+32-1
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,24 @@
66
//!
77
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html
88
9-
use rustc_ast::walk_list;
9+
use rustc_ast::{walk_list, BorrowKind};
1010
use rustc_data_structures::fx::FxHashSet;
1111
use rustc_hir as hir;
1212
use rustc_hir::def_id::DefId;
1313
use rustc_hir::intravisit::{self, Visitor};
1414
use rustc_hir::{Arm, Block, Expr, Local, Pat, PatKind, Stmt};
15+
use rustc_hir_pretty::qpath_to_string;
1516
use rustc_index::Idx;
1617
use rustc_middle::middle::region::*;
1718
use rustc_middle::ty::TyCtxt;
1819
use rustc_span::source_map;
1920
use rustc_span::Span;
21+
use rustc_type_ir::Mutability;
2022

2123
use std::mem;
2224

25+
use crate::errors;
26+
2327
#[derive(Debug, Copy, Clone)]
2428
pub struct Context {
2529
/// The scope that contains any new variables declared, plus its depth in
@@ -90,6 +94,12 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
9094

9195
let prev_cx = visitor.cx;
9296

97+
if let hir::BlockCheckMode::UnsafeBlock(src) = blk.rules
98+
&& matches!(src, hir::UnsafeSource::UserProvided)
99+
{
100+
static_mut_ref(visitor.tcx, blk.stmts);
101+
}
102+
93103
// We treat the tail expression in the block (if any) somewhat
94104
// differently from the statements. The issue has to do with
95105
// temporary lifetimes. Consider the following:
@@ -887,3 +897,24 @@ pub fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
887897

888898
tcx.arena.alloc(scope_tree)
889899
}
900+
901+
/// Check for use of mutable static
902+
pub fn static_mut_ref(tcx: TyCtxt<'_>, stmts: &[Stmt<'_>]) {
903+
for stmt in stmts {
904+
if let hir::StmtKind::Local(loc) = stmt.kind
905+
&& let Some(init) = loc.init
906+
&& let hir::ExprKind::AddrOf(borrow_kind, _, expr) = init.kind
907+
&& matches!(borrow_kind, BorrowKind::Ref)
908+
&& let hir::ExprKind::Path(qpath) = expr.kind
909+
&& let hir::QPath::Resolved(_, path) = qpath
910+
&& let hir::def::Res::Def(def_kind, _) = path.res
911+
&& let hir::def::DefKind::Static(mt) = def_kind
912+
&& matches!(mt, Mutability::Mut)
913+
&& loc.span.edition().at_least_rust_2024()
914+
{
915+
let span = init.span;
916+
let var = qpath_to_string(&qpath);
917+
tcx.sess.emit_err(errors::StaticMutRef { span, var });
918+
}
919+
}
920+
}

compiler/rustc_hir_analysis/src/errors.rs

+15
Original file line numberDiff line numberDiff line change
@@ -1329,3 +1329,18 @@ pub struct OnlyCurrentTraitsPointerSugg<'a> {
13291329
pub mut_key: &'a str,
13301330
pub ptr_ty: Ty<'a>,
13311331
}
1332+
1333+
#[derive(Diagnostic)]
1334+
#[diag(hir_analysis_static_mut_ref, code = "E0796")]
1335+
#[note]
1336+
pub struct StaticMutRef {
1337+
#[primary_span]
1338+
#[label]
1339+
#[suggestion(
1340+
style = "verbose",
1341+
code = "addr_of_mut!({var})",
1342+
applicability = "maybe-incorrect"
1343+
)]
1344+
pub span: Span,
1345+
pub var: String,
1346+
}

0 commit comments

Comments
 (0)