Skip to content

Commit d871657

Browse files
treat addr_of!(STATIC_MUT) implied deref as safe
The implied deref introduced during HIR->THIR lowering is only used to create place expressions, it lacks unsafe semantics.
1 parent ada5e2c commit d871657

File tree

4 files changed

+28
-9
lines changed

4 files changed

+28
-9
lines changed

compiler/rustc_mir_build/src/check_unsafety.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ struct UnsafetyVisitor<'a, 'tcx> {
3434
/// When inside the LHS of an assignment to a field, this is the type
3535
/// of the LHS and the span of the assignment expression.
3636
assignment_info: Option<Ty<'tcx>>,
37+
in_addr_of: bool,
3738
in_union_destructure: bool,
3839
param_env: ParamEnv<'tcx>,
3940
inside_adt: bool,
@@ -170,6 +171,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
170171
safety_context,
171172
body_target_features: self.body_target_features,
172173
assignment_info: self.assignment_info,
174+
in_addr_of: false,
173175
in_union_destructure: false,
174176
param_env: self.param_env,
175177
inside_adt: false,
@@ -449,12 +451,21 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
449451
}
450452
}
451453
}
454+
ExprKind::AddressOf { .. } => {
455+
self.in_addr_of = true;
456+
}
452457
ExprKind::Deref { arg } => {
458+
let allow_implicit_static_deref = self.in_addr_of;
459+
self.in_addr_of = false;
460+
453461
if let ExprKind::StaticRef { def_id, .. } | ExprKind::ThreadLocalRef(def_id) =
454462
self.thir[arg].kind
455463
{
456-
if self.tcx.is_mutable_static(def_id) {
464+
// We want to forgive only one deref, so addr_of!(STATIC_MUT) works
465+
// as one deref is a synthetic `*ptr` for a place expression
466+
if !allow_implicit_static_deref && self.tcx.is_mutable_static(def_id) {
457467
self.requires_unsafe(expr.span, UseOfMutableStatic);
468+
// In some cases we synthesize references to extern statics, however
458469
} else if self.tcx.is_foreign_item(def_id) {
459470
self.requires_unsafe(expr.span, UseOfExternStatic);
460471
}
@@ -956,8 +967,9 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
956967
hir_context: hir_id,
957968
body_target_features,
958969
assignment_info: None,
959-
in_union_destructure: false,
960970
param_env: tcx.param_env(def),
971+
in_addr_of: false,
972+
in_union_destructure: false,
961973
inside_adt: false,
962974
warnings: &mut warnings,
963975
suggest_unsafe_block: true,

tests/ui/consts/const_refs_to_static.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const C1: &i32 = &S;
99
const C1_READ: () = {
1010
assert!(*C1 == 0);
1111
};
12-
const C2: *const i32 = unsafe { std::ptr::addr_of!(S_MUT) };
12+
const C2: *const i32 = std::ptr::addr_of!(S_MUT);
1313

1414
fn main() {
1515
assert_eq!(*C1, 0);

tests/ui/consts/mut-ptr-to-static.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,9 @@ static mut STATIC: u32 = 42;
1616
static INTERIOR_MUTABLE_STATIC: SyncUnsafeCell<u32> = SyncUnsafeCell::new(42);
1717

1818
// A static that mutably points to STATIC.
19-
static PTR: SyncPtr = SyncPtr {
20-
foo: unsafe { ptr::addr_of_mut!(STATIC) },
21-
};
22-
static INTERIOR_MUTABLE_PTR: SyncPtr = SyncPtr {
23-
foo: ptr::addr_of!(INTERIOR_MUTABLE_STATIC) as *mut u32,
24-
};
19+
static PTR: SyncPtr = SyncPtr { foo: ptr::addr_of_mut!(STATIC) };
20+
static INTERIOR_MUTABLE_PTR: SyncPtr =
21+
SyncPtr { foo: ptr::addr_of!(INTERIOR_MUTABLE_STATIC) as *mut u32 };
2522

2623
fn main() {
2724
let ptr = PTR.foo;

tests/ui/static/addr-of-static-mut.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//@ check-pass
2+
3+
// see https://github.com/rust-lang/rust/issues/125833
4+
// notionally, taking the address of a static mut is a safe operation,
5+
// as we only point at it instead of generating a true reference to it
6+
static mut FLAG: bool = false;
7+
fn main() {
8+
let p = std::ptr::addr_of!(FLAG);
9+
println!("{p:p}")
10+
}

0 commit comments

Comments
 (0)