TL;DR: empty arrays are special cased in the compiler and it's safe because you can't ever dereference the pointer of a zero-length array, so there's no possible mutable aliasing.
RFC 1414, rvalue static promotion, discusses the mechanism by which values are promoted to static
values. It has a section about possible extensions for mutable references (bolding mine):
It would be possible to extend support to &'static mut
references,
as long as there is the additional constraint that the
referenced type is zero sized.
This again has precedence in the array reference constructor:
// valid code today
let y: &'static mut [u8] = &mut [];
The rules would be similar:
- If a mutable reference to a constexpr rvalue is taken. (
&mut <constexpr>
)
- And the constexpr does not contain a
UnsafeCell { ... }
constructor.
- And the constexpr does not contain a const fn call returning a type containing a
UnsafeCell
.
- And the type of the rvalue is zero-sized.
- Then instead of translating the value into a stack slot, translate
it into a static memory location and give the resulting reference a
'static
lifetime.
The zero-sized restriction is there because
aliasing mutable references are only safe for zero sized types
(since you never dereference the pointer for them).
From this, we can tell that mutable references to empty arrays are currently special-cased in the compiler. In Rust 1.39, the discussed extension has not been implemented:
struct Zero;
fn example() -> &'static mut Zero {
&mut Zero
}
error[E0515]: cannot return reference to temporary value
--> src/lib.rs:4:5
|
4 | &mut Zero
| ^^^^^----
| | |
| | temporary value created here
| returns a reference to data owned by the current function
While the array version does work:
fn example() -> &'static mut [i32] {
&mut []
}
See also:
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…