1
Fork 0

compiler: treat &raw (const|mut) UNSAFE_STATIC implied deref as safe

The implied deref to statics introduced by HIR->THIR lowering is only
used to create place expressions, it lacks unsafe semantics.
It is also confusing, as there is no visible `*ident` in the source.
For both classes of "unsafe static" (extern static and static mut)
allow this operation.

We lack a clear story around `thread_local! { static mut }`, which
is actually its own category of item that reuses the static syntax but
has its own rules. It's possible they should be similarly included, but
in the absence of a good reason one way or another, we do not bless it.
This commit is contained in:
Jubilee Young 2024-05-31 18:48:42 -07:00
parent ada5e2c7b5
commit 3fdd8d5ef3
9 changed files with 123 additions and 9 deletions

View file

@ -449,6 +449,24 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
}
}
}
ExprKind::AddressOf { arg, .. } => {
if let ExprKind::Scope { value: arg, .. } = self.thir[arg].kind
// THIR desugars UNSAFE_STATIC into *UNSAFE_STATIC_REF, where
// UNSAFE_STATIC_REF holds the addr of the UNSAFE_STATIC, so: take two steps
&& let ExprKind::Deref { arg } = self.thir[arg].kind
// FIXME(workingjubiee): we lack a clear reason to reject ThreadLocalRef here,
// but we also have no conclusive reason to allow it either!
&& let ExprKind::StaticRef { .. } = self.thir[arg].kind
{
// A raw ref to a place expr, even an "unsafe static", is okay!
// We short-circuit to not recursively traverse this expression.
return;
// note: const_mut_refs enables this code, and it currently remains unsafe:
// static mut BYTE: u8 = 0;
// static mut BYTE_PTR: *mut u8 = unsafe { addr_of_mut!(BYTE) };
// static mut DEREF_BYTE_PTR: *mut u8 = unsafe { addr_of_mut!(*BYTE_PTR) };
}
}
ExprKind::Deref { arg } => {
if let ExprKind::StaticRef { def_id, .. } | ExprKind::ThreadLocalRef(def_id) =
self.thir[arg].kind

View file

@ -939,9 +939,11 @@ impl<'tcx> Cx<'tcx> {
}
}
// We encode uses of statics as a `*&STATIC` where the `&STATIC` part is
// a constant reference (or constant raw pointer for `static mut`) in MIR
// A source Rust `path::to::STATIC` is a place expr like *&ident is.
// In THIR, we make them exactly equivalent by inserting the implied *& or *&raw,
// but distinguish between &STATIC and &THREAD_LOCAL as they have different semantics
Res::Def(DefKind::Static { .. }, id) => {
// this is &raw for extern static or static mut, and & for other statics
let ty = self.tcx.static_ptr_ty(id);
let temp_lifetime = self
.rvalue_scopes